Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
RE: RE: [platform-swt-dev] org.eclipse.swt.SWT

**Once again**, my original point was *not* about any specific SWT
classes; it was about openness in general and the usefulness of get/set.
Unfortunately, the "Point" class was used as an example and I followed
through on it.

My intention is *not* to suggest that we make any changes to SWT, but
unfortunately SWT was the example vehicle of "see, we don't need to have
getters/setters". Overall, I like the design of SWT, but the lack of
getters/setters will likely cause problems for people at some point.
(The most obvious example is UI builders, but non-UI builder use will
probably stick people as well.)

(I'm beginning to wish I hadn't gotten involved -- I delayed for quite
some time until folks started saying get/set was unnecessary...)


A big note about my suggested usage of Bridge
=============================================
I think you need to re-read what I wrote:

"If you're concerned about openness restricting your implementation
options, then you've hit the reason the GoF Bridge Pattern exists. You
can put any impl details you want in an "internal" class and call them
from the API class. This allows people to extend your API classes,
tweaking some parts if they want, leaving other behavior as is. Back to
my rule #4: In the API classes, all the methods should be public or
protected."

*** This does *not* state/imply/suggest/recommend that all classes be
Bridges. ***

If a class in a non-internal package is *open* per my rules of reuse,
and you're happy with that class' definition, there's no need for a
bridge. However, this restricts the types of changes that you can make,
as all the methods (the public/protected ones, which should be most if
not all of them) are pretty much promised to exist.

My mention of Bridge is that if you want more flexibility (ie, you're
concerned that refactoring may need to affect the available methods, and
possibly often), the Bridge pattern gives you that flexibility while
still allowing the non-internal class (the handle) to be completely
open.

If refactoring requires an open class to have significant method
changing, the class can be converted into a handle, calling the
refactored methods in a body. This doesn't always work cleanly, and may
require some API change, but often it can be done without disturbing the
open class' interface (available methods).


My Point: Make exposed classes *open* so they can be subclassed if
desired. Bridge may help, but is not the only solution.


Now to address your points. Keep in mind, though, that it sounds like
much of your POV comes from the angle that everything must be a bridge,
which is not what I said.


> First off, much of the Bridge pattern's strength comes from
> the ability to
> dynamically select and instantiate the internal
> implementation class at runtime.

Nope. The strength of Bridge is the separation of interface and
implementation. While this allows dynamic selection/replacement of
implementation detail, it's far from the major benefit.

> Bridge also makes it easier to hide implementation
> details that
> crosscut a class hierarchy at multiple points. [...]
> Bridge's main cost of course is that a parallel hierarchy must be
> constructed and maintained.

I'll agree.

> Some additional ugliness results from
> difficulties in managing the lifecycle of the linked objects.
>  You can think
> of the interface object and its backend implementation object
> as forming a
> handle-body pair except that state may be distributed or
> mirrored across the
> two objects.  Garbage collection alleviates some of this concern.

Here's where your argument falls apart IMHO -- nothing says that the
handle has to keep any state at all!
In fact, if you keep state in the handle, you lose most of the benefits
of Bridge (many of the "problems" you note below).

The handle should be just the set of methods that are exposed to the
client. These methods just delegate to the body, and should all be
public or protected. This allows subclasses to extend and modify.

If dynamic body switching isn't a goal (which is true, as you point out,
for SWT), the handle can know explicitly which body it wants to use and
directly use it. That body would live in an "internal" package. Because
it would show up in the handle code (if the client looks at the source),
it may be tempting for the client to use, so employing one of the
factory patterns could be useful to further hide the body, but not
absolutely necessary.)


> One can directly analyse the effects of applying the Bridge pattern to
> windowing toolkits by comparing AWT with SWT.  A few observations:
>
> 0) For lifecycle issues, AWT introduced an ugly hack called
> "addnotify()".
> This is compounded by the brain-dead way in which AWT's
> containers work.
> Now all widgets have to worry about an extra "not yet
> realized state".  Note
> that the Bridge pattern does not require this sort of thing.

> 0) State information about each widget must be duplicated between the
> implementation and interface classes in case the
> implementation class goes
> away.  Again, not strictly Bridge pattern's fault.  More due
> to a design decision gone wrong.

I'm not sure why you make these points. I agree that addNotify() and the
duplication of state was a bad decision in AWT. As you point out, Bridge
doesn't require this...


> 1) Bridge pattern requires a parallel class hierarchy.  This
> is evil.  In OO
> languages that lack native method delegation facilities, this
> results in a
> lot of messiness to do with duplicating interfaces everywhere.  We're
> talking huge gobs of boilerplate code to maintain.  Ugh.

I suspect that if the decision to use Bridge were made, the developers
would have created some macro facilities or add-ons to Java. I was
tinkering with an auto-delegation precompiler for Java that would allow
things like:

  class A implements B using C c {
  }

which would automatically create all methods required by interface B and
delegate them all to and instance of class C (named c). Any of those
methods could be overridden in the body of class A. Delegating to
multiple classes for a single interface would have required a bit more
specification, perhaps

  class A implements B using C c {
    D d;
    delegate foo() to d;
  }

where most are delegated to c, and a few to d.

Anyway, that's beside the point. When lots of duplicate code is
necessary, someone will create a facility to deal with it and make it a
significantly smaller issue.


> 2) SWT does not require dynamic selection and instantiation of
> implementation objects.  [...]

I agree, *but* that's not the goal of the Bridge pattern. The goal is
separate maintenance of interface and implementation. When you expose
something as API (the handle), the client can depend on that interface
not changing (or changing with a much lower frequency). You can change
the body at will. The also allows the client to subclass the handle and
reuse the bodies.

> 3) With extra code for delegation come increased demands on
> resources.  More
> classes => bigger class files => longer load times => poorer execution
> times.  One might hope that a clever JVM would inline out
> delegation.  This
> is only possible if the delegate object is stored in a
> "final" field.  Of course, AWT doesn't do this...

I'm on the fence here. While I see your point, I don't see the extra
method calls as a big expense. Also, keep in mind the way classes are
loaded in Java; not everything is loaded at once, so the extra time is
very spread out, and the majority of the delegation methods are quite
small.

If you're not looking for runtime replacement (like SWT per #2 above),
making the body reference final is not a problem...


> 4) Don't get me started on the foolishness of trying to
> subclass interface
> classes in the Bridge pattern.  Want a template method?
> Can't have one!
> You'd need to let the implementation classes know about the interface
> classes.  But you can't have that...  So all you need is an
> Observer right?
> Or you can move some of the sequencing logic up to the interface class
> level.  This sort of reasoning quickly balloons out of proportion.

Who says a Bridge cannot have a pointer from body to handle? With
template method, you're only calling methods that exist in the top-level
handle and body classes anyway. So if the body had a ref to the handle,
there's absolutely no reason that either side couldn't employ template
methods that cross the bridge.

Remember that patterns are not absolutes; they're merely written down
examples of common ways to solve problems, and are intended to be
tweaked. The concepts are what's important; not the Gof-specified
implementation.

> 5) So, what we're really buying with Bridge in this case is a
> very expensive
> wrapper to handle some annoying visibility and (possibly) binary
> compatibility issues.  These issues would go away if Java
> provided something
> more like the ML module system for extracting multiple views
> (ML structures) of an interface.

I wasn't familiar with ML until now. I did a brief read, and it sounds
to me like ML signatures/structures allow you to explicitly define which
items are visible to outside users. If I "get it", a sig acts like a
filter that exposes certain functions, and when applied to a structure
def to create an object, you essentially hide any functions that aren't
in the sig *for that object*. Other objects of the structure type could
be filtered differently. Did I get the point?

If I got that, I'm not sure how that applies here, as we're talking
about the type definitions themselves and subclassing them, not the
runtime usage of them...

The general thought I had about Bridge was that it allows the entire
class defined in a non-internal package to be reusable while giving you
the flexibiilty to change implementation detail anytime. Again, if the
non-internal class is already open per my rules of reuse, a Bridge is
unnecessary.


> I honestly think that this thread has gone on much too long.
> There's simply
> no sense arguing philosophy until the time comes to develop
> SWT-NG in 4-5
> years (just speculating).  And then you know what?  It'll probably be
> implemented using whatever new fancy tools are in vogue like
> Aspect Oriented
> Programming.  Many "mistakes" again will be made.  Different ones.

My part of the discussion is not SWT specific. My part of the discussion
was on the merits of keeping classes open. My point isn't "let's change
SWT"; the point is to try to get folks to think about things from a more
open point of view, so that as more code is developed (and as people
start thinking of things like SWT-NG), they'll be thinking in more open
terms.

Think "is there really a 'need to protect'?"


> [more on "SWT attack" snipped -- not my intent, but others brought it
up as an example so I used it.]

-- Scott




Back to the top