more use of interfaces for widgets ?

0 views
Skip to first unread message

Ed

unread,
Aug 14, 2008, 7:00:58 AM8/14/08
to Google Web Toolkit Contributors
I requested in the issue tracker for more widget interfaces:
http://code.google.com/p/google-web-toolkit/issues/detail?id=2146

Joel mentioned that this isn't so easy and told me to discuss this in
the contributor group, so here it.

In the issue you can read an example why interfaces would required If
that's not enough, let me know and I will think of more examples.

Please some feedback on why not/how to add more interfaces to (at
least) GWT widgets ?

Joel Webber

unread,
Aug 15, 2008, 10:01:34 AM8/15/08
to Google-Web-Tool...@googlegroups.com
If I may quote from the issue tracker, to get the suggestions inline:

> Please use more interfaces.
> Why ?
> Suppose you have your own widget that extends Composite widget and that
> implements SourcesFocusListenerEvent.
> Now supose you  have a method or class constructor that want Widgets as
> arguments that implement SourcesFocusListenerEvent.
> At this moment with GWT: this is very hard to do in a nice way...
> The only way to do this is to require that the argument is of type Widget
> and then in the method check that it implements
> SourcesFocusListenerEvent.... and do some casting everytime you need this
> ... :(... not sooo nice... 
> Because Java can't extend multiple classes but can implement more then one
> interfaces.... It would be better to have Widget implement an Interface,
> something like WidgetIntf. Such that you can composite your own interface
> that implements the SourcesFocusListenerEvent interface and WidgetIntf
> which is then implemented by your Composite widget.... and volica... nice
> thight java coding... ;)...
> I hope this will be used... (I also submitted an similar issue about the
> insert() method on the HOrizontal/VerticalPanel...

to express this in code, as a rough outline (please let me know if I mis-express the scenario you're describing):

public class MyWidget extends Composite implements SourcesFocusEvents {
  private Widget wrapped;

  public MyWidget(Widget wrapped) {
    assert wrapped implements SourcesFocusEvents : "wrapped widget must source focus events";
    this.wrapped = wrapped;
  }

  public void addFocusListener(FocusListener l) {
    // Or I suppose you perform the cast 
    ((SourcesFocusEvents)wrapped).addFocusListener(l);
  }

  // etc.
}

This is definitely a pain point, and it comes up in several different circumstances, e.g.,

button.addClickListener(new ClickListener() {
  public void onClick(Widget sender) {
    // Is sender a button or not? What if this listener is hooked to several different widget types?
  }
});

It doesn't appear to me that creating an "IWidget" base interface for widgets would really help much here. You'd end up having to create a baroque type hierarchy something like this:

interface IWidget { }
class Widget implements IWidget { }
interface ClickableWidget extends IWidget, SourcesClickEvents { }
interface FocusableWidget extends IWidget, SourcesFocusEvents { }
interface ClickableFocusableWidget extends ClickableWidget, FocusableWidget { }
class Button extends Widget implements ClickableFocusableWidget { }

so that you could write MyComposite(FocusableWidget) { /* etc */ }

The only solution I know of is to use Java 1.5 generics to specify the exact intersection types you want, without creating a new name for each possible combination. To address your first example:

public class MyWidget<T extends Widget & SourcesFocusEvents>
    extends Composite implements SourcesFocusEvents {

  private T wrapped;

  public MyWidget(T wrapped) {
    this.wrapped = wrapped;
    initWidget(wrapped);
  }

  public void addFocusListener(FocusListener listener) {
    wrapped.addFocusListener(listener);
  }

  // etc.
}

The fact that Widget is a class and not an interface doesn't really make a difference one way or another here. You could also use this to address the listener problem, like so:

public class Button extends Widget implements SourcesClickEvents { }

public interface ClickListener<T extends Widget & SourcesClickEvents>
    extends EventListener {
  void onClick(T sender);
}

button.addClickListener(new ClickListener<Button>() {
  public void onClick(Button sender) {
    // whatever
  }
});

I'm not 100% sure we could make a change like this without causing a lot of confusion, because at a bare minimum everyone would have lots of unparameterized type warnings all over their code. But it's worth thinking about.

Fred Sauer

unread,
Aug 16, 2008, 12:53:49 PM8/16/08
to Google-Web-Tool...@googlegroups.com

> I hope this will be used... (I also submitted an similar issue about the
> insert() method on the HOrizontal/VerticalPanel...

Related to this discussion is perhaps the InsertPanel interface:
  http://code.google.com/p/google-web-toolkit/issues/detail?id=1112

Fred Sauer
fr...@allen-sauer.com

Ed

unread,
Aug 18, 2008, 9:41:21 AM8/18/08
to Google Web Toolkit Contributors
Let see if it works now. I answered the posts, but it never appeared
in the thread :(...

Thanks for pointing it out to me Fred, I linked the issues together
through some comments.

Ed

Ed

unread,
Aug 17, 2008, 4:53:34 AM8/17/08
to Google Web Toolkit Contributors
Thanks for pointing that out Fred.
I added some comments to links these issues together.

Ed

unread,
Aug 17, 2008, 5:23:28 AM8/17/08
to Google Web Toolkit Contributors
He Joel,

Let me see if I understand you correctly.
Basically you suggesting two kind of solutions:
1) Introducing interfaces like requested in the issue.
2) Using generics.

My 50 cent:
2) I would't go there for the reasons you gave above. It get scary,
also if you think about it that there are still many developers that
don't really understand the details of Generics and rather avoid
them....

1) Introducing interfaces seems like a good solution to me.
Wny?:
- Instead of with Generics, if you don't want to use them, you don't
need to. They are just mindless "things" that are out there and you
can use them to compose your components, but you don't need to if you
don't want to..

> It doesn't appear to me that creating an "IWidget" base interface for
> widgets would really help much here. You'd end up having to create a baroque
> type hierarchy something like this:

I don't really understand you point here?
I understand that it gives a lot of extra interfaces, but isn't that
the consequence of:
a) Java, not being able to extend more then one class?
b) Necessary if you want to offer an extendable/user-friendly/
flexible/... API?

Especially this last point is important I think. Just have a look at
the Spring framework. They have two hierachies: one for the classes
and one for the interfaces.. You easily lose overview but the
interfaces give a lot of flexibility to extend the Spring framework
and add your own components.
I would have had great problem if they wouldn't have done that.. As
such I think you can't do without a clear hierachy of interfaces if
you want to comply b).
From a design point of view: I also think it gives you a good overview
of what you framework really offers and can be extended.
I wouldn't like to think of the java SE Collection framework without
the interfaces :(

Your example showed the problem well, but let me point out some more
to show the ugly coding of no-interfaces:
I have a WidgetGroup class with Widget CRUD actions. Snippet:

public class WidgetGroup {

/**
* @param widget
* must implement {@link ItemSelectable}
*/
public void addWidget(final Widget widget) {
assert widget instanceof ItemSelectable: "boem";
.....
}


/**
* @param widget
* must implement {@link ItemSelectable}
*/
public void insertWidget(final Widget widget) {
assert widget instanceof ItemSelectable: "boem";
.....
}
....
...
}


As you can see: the specified widget must implement ItemSelectable.
Snippet:

public interface ItemSelectable extends SourcesClickEvents, HasData {
void setSelected(boolean selected);
boolean isSelected();
void setEnabled(boolean enabled);
boolean isEnabled();
}

I think you see where I am going. Everytime I have to check if it
implements the correct interface :(... I can tell you that I do these
constructions a lot as I did a lot of coding already... I have more
examples like MutationList, ButtonBar, which all have the same kind of
constructions... If you want more examples, just let me know please?
Another snippet about a Slide In effect:

public void slideInPanel(final Panel mainPanel, final Widget widget,
final SlideInSpeed style, final int index) {
if (index == -1) { // add at end
mainPanel.add(widget);
}
else {
if (mainPanel instanceof FlowPanel) {
((FlowPanel) mainPanel).insert(widget, index);
}
else if (mainPanel instanceof HorizontalPanel) {
((HorizontalPanel) mainPanel).insert(widget, index);
}
else if (mainPanel instanceof VerticalPanel) {
((VerticalPanel) mainPanel).insert(widget, index);
}

else {
throw new CodeRuntimeException("err-effects-01", " panel type: " +
mainPanel.getClass().getName());
}
}

// slide the widget into his parent
Effects.slideIn(widget.getElement(), createEffectConfig(style),
Direction.DOWN);
}

Beautiful coding not? :(
This is also solved if I simple would have an interface like suggested
in issue 1112, like mentioned by Fred:
http://code.google.com/p/google-web-toolkit/issues/detail?id=1112






Joel Webber

unread,
Aug 19, 2008, 12:53:02 PM8/19/08
to Google-Web-Tool...@googlegroups.com
It looks like you're describing two separate cases here, one of which seems much more achievable than the other.

The simpler of the two could be described as "add more classes within the type hierarchies of existing types, so that we can operate upon them in their more abstract forms". I'm referring to the SlideInPanel example at the bottom, where it clearly wants an "InsertPanel" type to operate on, and because of its absence must switch on panel type, which does indeed suck! I'm very much in favor of this kind of change.

I still think some issues remain with the other proposal, though. Let me try and characterize it as the "type intersection problem". Your WidgetGroup (which wants a SelectableWidget interface) describes this problem well. In my earlier message I started drawing out a type hierarchy that I thought was a proof of its impossibility by reductio ad absurdum. Let me take it a bit further by extending it a bit more:

  // Basic characteristic interfaces
  interface IWidget { }
  interface SourcesClickEvents { }
  interface SourcesFocusEvents { }
  interface HasText { }
  interface HasHTML extends HasText { }

  // Cross-product interfaces
  interface ClickableWidget extends IWidget, SourcesClickEvents { }
  interface FocusableWidget extends IWidget, SourcesFocusEvents { }
  interface ClickableFocusableWidget extends ClickableWidget, FocusableWidget { }

  // Concrete classes
  class Widget implements IWidget { }
  class Button extends Widget implements HasHTML, ClickableFocusableWidget { }

But wait, "Button extends Widget implements HasHTML, ClickableFocusableWidget"? But what if I need to create a collection of widgets that sets their values (i.e. text) whenever they're clicked on? That seems like a perfectly reasonable use-case. Well, I've got to go back and create *another* couple of interfaces, like so:

  interface ClickableWidgetHasHTML extends ClickableWidget, HasHTML
  interface ClickableFocusableWidgetHasHTML extends ClickableWidgetHasHTML, SourcesFocusEvents { }

and modify Button like so:

  class Button extends Widget implements ClickableFocusableWidgetHasHTML { }

so that I can write:

  void initWidgetToChangeValueWhenClicked(final ClickableWidgetHasHTML w, final String value) {
    w.addClickListener(new ClickListener() {
      public void onClick(Widget source) {
        w.setText(value);
      }
    });
  }

As you can see, the cross-product of N characteristic interfaces creates an N-dimensional matrix, each element of which describes some use-case, many of which are legitimate. This quickly becomes intractable, as the number of specific interfaces increases with the Nth power of the number of characteristic interfaces. And the name length increases linearly in the number of interfaces present on a widget -- each widget's specific interface name would basically contain its full type declaration. That's not just Baroque, it's practically Rococo!

Earlier, I proposed using generics and intersection types to resolve this specific problem -- and I do agree that it gets complicated pretty fast, and that many developers will have a hard time following it. I'm just not sure I know of a better way to solve this problem without extending Java to use a structural type system.

As always, if I've somehow mischaracterized the case you're describing, or failed to notice a simpler solution, please let me know!

Thanks,
joel.

Ed

unread,
Aug 20, 2008, 4:32:42 AM8/20/08
to Google Web Toolkit Contributors
Thanks for you detailed explanation.
I understand your point Joel, but this in't really a GWT issue, but
rather a Java issue.

The case you describing is extreme and even do you are saying it's a
"reasonable use case" I think that developers that come up with these
kind of absurb design issues, need to think it over. I was just
thinking about my components, but never came up with something like
that...
Ofcourse it's possible but I doubt it's practically and that people do
this.

Anyway, it's up to the developer to use the GWT interfaces the way he
wants, so if he comes up with these kind of absurb number of
interfaces that's his choice.

But let's us go back to the real issue: more interfaces in GWT. I
think if GWT introduces about maybe 10 interfaces it will solve ugly
implementation issues as described above. What's wrong with that? So
you will get interfaces like IWidget, IInsertPanel, etc... Not so much
but it do solves quite a few problems. And then if developers want to
compose more interfaces and let them explode, that's their choice
not... their problem, or is that said "too easy"..

Again: suppose that Spring wouldn't have introduced all these API
interfaces it has now: I couldn't have composed the "elegant" Spring
components that I have now.....

Or am I missing something here ? I have the feeling you want to
restrict the interface uses to "protect" the developers, am I
right?.... But is that a good enough reason to not add more
interfaces, whereas it solves quite a few problems?

BTW: why are there interfaces for the Listeners, like the
SourceClickListeners? It looks like GWT introduces some interfaces but
for some reason then stopped introducing more.... but why ?



Ray Cromwell

unread,
Aug 20, 2008, 5:01:24 AM8/20/08
to Google-Web-Tool...@googlegroups.com
Regardless of what's decided, please don't start naming everything IFoo/CFoo :)

Emily Crutcher

unread,
Aug 20, 2008, 10:04:20 AM8/20/08
to Google-Web-Tool...@googlegroups.com
Currently the design principles we are using is that we are happy to introduce characteristic interfaces, but not more complex "bag of functionality" interfaces. So, for instance, HasElement() might be introduced on widget, as well as HasSinkEvents(), as introducing those interfaces do not lock us into an unexpandable Widget API.
--
"There are only 10 types of people in the world: Those who understand binary, and those who don't"

Bruce Johnson

unread,
Aug 20, 2008, 4:13:14 PM8/20/08
to Google-Web-Tool...@googlegroups.com
I think most everyone agrees that the idea of characteristic interfaces (that's what we tend to call them) is a good idea. The challenge is deciding (1) which interfaces are appropriate and not superfluous and (2) designing such that we aren't likely to need to change them in the foreseeable future.

For framework-y code like the widget library, our biggest collective challenge as a community is avoiding mistakes (even those that seem like a good idea "at the time") that ultimately will haunt us. So, we're going to always be conservative and insist on real-world use cases to justify adding stuff.

For anyone interested in this, I'd suggest the right way forward is to explain your use cases, where the widgets are currently lacking, and then  some vague suggestion of how you think it might be solved by adding a new interface. 

-- Bruce

Ed

unread,
Aug 20, 2008, 4:27:23 PM8/20/08
to Google Web Toolkit Contributors
Good point Emily.
To get a better understanding, could you please give me a bit more
details why a functionality interface like IWidget (don't mention the
name I know it's stupid) would give problems?
I think you mean being to able to easily remove/add functionality
methods in the future.. but I am not sure if I understand you
completely.

I think it's a good idea to add interfaces like HasElement,
HasSinkEvents, HasStyles, etc... but because these interfaces are so
trival might it then not be an idea to collect them together in a kind
of basic IWidget interface ?

If these interfaces, like HasElement, etc.. would be introduced, how
would they then be used in the GWT widgets ?... I can imagine that
these interfaces together form a kind of IWidget functionality
interface and might give the same "lock-in" problem... or not ?

Ed

unread,
Aug 21, 2008, 10:48:50 AM8/21/08
to Google Web Toolkit Contributors
> For anyone interested in this, I'd suggest the right way forward is to
> explain your use cases, where the widgets are currently lacking, and then
> some vague suggestion of how you think it might be solved by adding a new
> interface.

Thanks Bruce.
To make things more concrete I tried to come up with a more concrete
proposal which don't seem so easy..

I think that the problem in the above described use case, the
WidgetGroup can be solved if the Panel.add(Widget) would take an
interface, something like the silly IWidget interface, as input
argument instead of the class Widget.
In this case I would be able to compose a new Interface (like Joel
mentions above):
SelectableWidget extends IWidget, Selectable
that will be used in my add(SelectableWidget widget) method of the
WidgetGroup class. As such that it will be both valid for further
processing in the WidgetGroup class as selectable item and it will be
a valid input for, for example the VerticalPanel.add(IWidget), that
presents the WidgetGroup....

I don't see an other way of solving this... please some feedback?
This brings me back to my remark else where in this thread:
Introducing interfaces is one thing, but how it GWT going to use them,
otherwise id doesn't make much sense.

Another use case: I have a Form class that holds FormFields. Example
of FormFields are TextField and CheckboxField that contain all kind of
validation and common stuff.

I separated the logical and physical attachment of the FormFields to
the Form by injecting a InsertPanelWrapper (looks a bit the same like
issue 1112 like mentioned by Fred above).
Why do I want to separated these?: It gives me the flexibility to
insert the panel that I want, and as such place the forms where ever I
want. In my case the form fields are not all nice sequential but
scatered around the page with explanation text between them. By
separating the two I can do this nicely.

My InsertPanelWrapper contains methods like add(..), insert(..),
getWidgetCount(..). It's a combination of the upcomming IndexedPanel
and InsertPanel. However mine contains one extra method: getPanel()
that returns the actual Panel being wrapped, as I need to feed the
encapsulated panel to the initWidget(Widget) of the Composite widget
that is extended by the Form class.
The pointing I want to make here, is again that I think that also here
the method initWidget(Widget) should take an interface as input stead
of the class Widget.
So where do we start?... Some extra interfaces like the ones that are
introduced by Scott Blum are very helpfull, but still doesn't solve
"all" my problems (not that it needs to, but at least most of them)

Please some feedback on the above. I also would like to hear the
opinion of Scott Bruce.

Ed



Ed

unread,
Aug 26, 2008, 4:25:45 AM8/26/08
to Google Web Toolkit Contributors
Can we please continue this discussion and come to a decision/plan?
I think it's a rather important issue.

Joel Webber

unread,
Aug 26, 2008, 8:47:04 AM8/26/08
to Google-Web-Tool...@googlegroups.com
No one's disagreeing that it's an interesting and important topic. But you also have to be aware that this is a complex topic that won't get resolved overnight. Many of the people on this group are very busy with other things as well (e.g. getting 1.5 out the door), and can't devote energy daily to every single topic that comes up. If we did, we'd never get anything done.

I don't mean to say that we shouldn't continue the discussion either -- I've been thinking about it quite a lot myself. But as I said, the 'correct' answer is not obvious, and we really can't afford to jump into anything too quickly.

Ed

unread,
Aug 26, 2008, 9:20:27 AM8/26/08
to Google Web Toolkit Contributors
Thanks Joel,

I fully understand that, that's why I would like to make a plan/
decision such that it won't get forgotten and I know where we stand (I
don't know what has what priority)

If the decision is: "it's in the issue tracker and we will get back to
it asap" ... fine... at least I know then that this discussion will
be picked up later and it's not for nothing.

In the meantime I made a link from the issue to this discussion.

Any idea when this issue will be picked up and a design plan will be
made ? and in which release?

Ed

Bruce Johnson

unread,
Aug 26, 2008, 12:00:22 PM8/26/08
to Google-Web-Tool...@googlegroups.com
Ed, I do see that there could be some useful improvements to come out of this.

At the same time, why is there urgency? People are currently building and testing very large and complex apps with GWT.

I have this funny feeling that you may be fixating on a particular formulation in your code that is necessitating the changes you propose, when in fact there are plenty of other ways to get the same thing done.

Can you talk about the high-level motivations for these types of changes? I'm not talking about things like, "I want to write some code that looks like <this>." Instead, I would expect that you'd have some concrete descriptions of how you can't properly test your code, or maybe a performance consideration. Or maybe you're wanting to create a library that needs some recurring abstraction in order to enable a significantly more convenient way of approaching UI construction.

We're always going to be conservative on topics like these, and the burden of proof is on the person wanting to change the status quo (i.e. you :-).

Ed

unread,
Aug 26, 2008, 12:19:00 PM8/26/08
to Google Web Toolkit Contributors
Hellu Bruce,

Thanks for your time.

I think we have some misunderstanding here.
Let me try to clear some things:

BTW: did you read the whole post?
Most of your answers to ur questions can be found in this post.

Anyway: nope it's not urgent and no I am not fixating on a particular
part of the post. The motivation you can find in the above, like the
general remarks and the use cases (not only talking about code).
Like mentioned above I am talking about many gwt code that I wrote the
last few years, so it's absolutely not urgent and I do get around
without the changes. But with the experience that I have till now I
think above you find a good motivation why I request the change.

Anyway: my last point was all about knowing where we stand and where
we go. Don't forget you are sitting in the heat and I am pretty far
from that so I have little idea how this issue is handled and picked
up.

I was just worried about that this discussion would be lost and
forgotten, that's all. Baically Joel already gave most of the answer I
was looking for.
Like mentioned, I also linked this discussion to the issue request,
such that the developer(s) assigned to it will have maybe a quick
start with this discussion. And ofcourse I more then willing to help
those developers!

>Ed, I do see that there could be some useful improvements to come
out of
>this.

Thanks Bruce, these were more the answers I was looking for so that I
hope you guys do something with it....

Good luck with the testing.





Reply all
Reply to author
Forward
0 new messages