Possible GWT.create() Improvements (link)

172 views
Skip to first unread message

Brian Slesinsky

unread,
Aug 9, 2013, 4:24:19 PM8/9/13
to GWTcontrib
Hi, I've published a document [1] with my thoughts on some of the GWT.create() proposals. This doesn't cover everything we've discussed but I think it's a start. If you're on this mailing list you should be able to comment.

- Brian

[1] https://docs.google.com/document/d/1MDqiBEMl7dylYliAceLBBxGFAlSvkQB9b-kSlnKmZBk/edit?disco=AAAAAGXMcRI#

Goktug Gokdogan

unread,
Aug 9, 2013, 7:16:55 PM8/9/13
to google-web-toolkit-contributors
I think in the long-run we should separate the two concepts that is being tackled by GWT.create today.

First purpose is the class replacement, especially used by permutations. I think this one should not have anything to do with GWT.create. We can do any class replacement in compiler without requiring a call to GWT.create. This is similar to super-sourcing and can be solved similar and perhaps together.

Second purpose is for triggering generators and what most of the proposal are about.

As Roberto and perhaps others have been bringing up, it is best to follow regular java code generation practices in GWT.

That means for the long-term we can mostly rely on AnnotationProcessors.
There are many advantages of that:
  1. Not GWT only - continue sharing code with server (JRE), client(GWT) and mobile(Android).
  2. IDE support: IDE can trigger codegen (esp. for debugging)
  3. Parallelizing the compilation and ease moving from JDT into java 8 compiler plugin.
  4. Reusing knowledge from java world and lower the barrier for entry to generators.


With that move, deferred binding definition for code generator can be just about providing the naming conventions such as "<class_name> -> <class_name>$Generated".
Based on the rule, when the compiler sees GWT.create(A.class), it can be turned into "new A$Generated()" and expect the generated code to be there.

The reason I'm bringing this up is; for any proposal I think it is best to keep it feasible w.r.t this aspect and not push us into a corner for the long run.


--
http://groups.google.com/group/Google-Web-Toolkit-Contributors
---
You received this message because you are subscribed to the Google Groups "GWT Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-co...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Thomas Broyer

unread,
Aug 10, 2013, 11:15:03 AM8/10/13
to google-web-tool...@googlegroups.com
There aren't really two concepts: you can mix and match generate-with and replace-with for the same type, and/or switch from one to the other over time.

Actually, replace-with is only a shorthand for a generator returning a constant value (of a class that already exists).

Ray Cromwell

unread,
Aug 10, 2013, 1:00:29 PM8/10/13
to google-web-toolkit-contributors
I don't think APT is good enough. Java8 has a compiler plugin API for code-gen that might work. APT has limitations that make it problematic to replace generators. Stephen Haberman brought this up at the GWT meetup.

John A. Tamplin

unread,
Aug 10, 2013, 1:28:36 PM8/10/13
to Google Web Toolkit Contributors
On Fri, Aug 9, 2013 at 7:16 PM, Goktug Gokdogan <gok...@google.com> wrote:
I think in the long-run we should separate the two concepts that is being tackled by GWT.create today.

First purpose is the class replacement, especially used by permutations. I think this one should not have anything to do with GWT.create. We can do any class replacement in compiler without requiring a call to GWT.create. This is similar to super-sourcing and can be solved similar and perhaps together.

I don't see how it is similar to super-sourcing, as you need to dynamically select which class goes on there. For example, think about implementing GWT.create(SomeLocalizableSubclass).  There are hundreds of locales, and different classes are going to have different implementations so you have to make the substitution decision for each one of them separately.

Are you proposing to hook new Foo and substituting the class?  Where does the compiler get the knowledge to know which class to substitute?  I don't think you want to build all the knowledge of the ClientBundle generator into the compiler, for example.
 
Second purpose is for triggering generators and what most of the proposal are about.

As Roberto and perhaps others have been bringing up, it is best to follow regular java code generation practices in GWT.

That means for the long-term we can mostly rely on AnnotationProcessors.
There are many advantages of that:
  1. Not GWT only - continue sharing code with server (JRE), client(GWT) and mobile(Android).

You can use shared.GWT.create today in all those environments.
 
  2. IDE support: IDE can trigger codegen (esp. for debugging)

My experience with this has been pretty poor, and running GWT with -gen is at least as useful.

--
John A. Tamplin

Brian Slesinsky

unread,
Aug 10, 2013, 2:18:22 PM8/10/13
to GWTcontrib

  2. IDE support: IDE can trigger codegen (esp. for debugging)

My experience with this has been pretty poor, and running GWT with -gen is at least as useful.

Also, Super Dev Mode gives you access to all the generated code. You can either use the browser's debugger with SourceMaps turned on (which also allows you to set breakpoints in generated code), or you can browse the source code directly on the codeserver.

It would be nice if we somehow got this working with an IDE, though.

- Brian


--
John A. Tamplin

John A. Tamplin

unread,
Aug 10, 2013, 2:23:31 PM8/10/13
to Google Web Toolkit Contributors
On Sat, Aug 10, 2013 at 2:18 PM, Brian Slesinsky <skyb...@google.com> wrote:

  2. IDE support: IDE can trigger codegen (esp. for debugging)

My experience with this has been pretty poor, and running GWT with -gen is at least as useful.

Also, Super Dev Mode gives you access to all the generated code. You can either use the browser's debugger with SourceMaps turned on (which also allows you to set breakpoints in generated code), or you can browse the source code directly on the codeserver.

It would be nice if we somehow got this working with an IDE, though.

I am saying my experience with IDE integration of code generation, whether protoc, APT, etc, has been pretty poor.  For example, at work I have taken to running protoc outside the IDE and reimporting it, rather than putting up with the IDE integration.  Ie, exactly what I can do with GWT today.

--
John A. Tamplin

Andrés Testi

unread,
Aug 10, 2013, 3:23:50 PM8/10/13
to google-web-tool...@googlegroups.com
This reminds me a lot of Scala macros research. As you probably know, Scala solves code-gen issues with experimental support for several kinds of macros, distinguishing clearly between expression-level and type-level code generation/rewriting.
APT covers only a fraction of type-level generation, while GWT.create() covers type-level and a little of expression-level rewriting. 
In standard JRE applications, expression-level is solved with runtime reflection, but in GWT, we must rely on GWT.create(). 
We always need expression-level handles to get access to the instances of the generated classes. Take a look at Dagger, injections are generated with APT (type-level)  and expression-level handles are done with ObjectGraph by means of runtime reflection:

// APT can't save us here, we need runtime reflection
ObjectGraph objectGraph = ObjectGraph.create(new DripCoffeeModule());

APT and GWT.create() are complementary done the lack of runtime reflection support in GWT. In this sense, I think the Ray's proposal is a step forward. We can't get rid off GWT.create(), but we can hide it as possible from end users. Only API authors should treat with GWT.create(). 
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscribe@googlegroups.com.

Andrés Testi

unread,
Aug 10, 2013, 3:35:05 PM8/10/13
to google-web-tool...@googlegroups.com
I miss this line in my dagger example:

CoffeeApp coffeeApp = objectGraph.get(CoffeeApp.class);

Brian Slesinsky

unread,
Aug 10, 2013, 4:42:08 PM8/10/13
to GWTcontrib
Now that I understand it (hopefully), I think Ray's proposal is a good way to define new API's by writing Java wrappers that configure generated objects at runtime. Adding parameters to GWT.create() calls seems somewhat orthogonal as a way to pass arguments to generators at compile time.

As often happens with language extensions, when you put them together, things get more complicated but also more expressive; if GWT.create() takes extra arguments then these should also be literals that you can accept in a user-defined create method.


To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-co...@googlegroups.com.

John A. Tamplin

unread,
Aug 10, 2013, 4:47:53 PM8/10/13
to Google Web Toolkit Contributors
On Sat, Aug 10, 2013 at 4:42 PM, Brian Slesinsky <skyb...@google.com> wrote:
Now that I understand it (hopefully), I think Ray's proposal is a good way to define new API's by writing Java wrappers that configure generated objects at runtime. Adding parameters to GWT.create() calls seems somewhat orthogonal as a way to pass arguments to generators at compile time.

As often happens with language extensions, when you put them together, things get more complicated but also more expressive; if GWT.create() takes extra arguments then these should also be literals that you can accept in a user-defined create method.

It doesn't have to all be literals -- you could imagine that the generator would be able to accept them as constructor arguments for the generated class.  Of course, specifying which can be expressions and which must be literals (or things the compiler can compute at compile time, perhaps even inlining calls to get to the literal), and doing that in such a way to get good feedback to the developer isn't trivial.

--
John A. Tamplin

Goktug Gokdogan

unread,
Aug 12, 2013, 1:13:20 AM8/12/13
to google-web-toolkit-contributors
Even though the current form is pretty flexible and you can mix and match the two, it doesn't mean it makes sense to do so. I'm having hard time thinking about out a good use case that would make a single complex mix and match more appealing than having a separate group of class replacements and a codegen (AFAIK, there is not even single example in the GWT-SDK itself). Actually separating the two can result in something much more useful&powerful [*].

GWT may treat them similarly and call it "deferred binding" and that is what it is from the compiler perspective. However IMHO, it looks like the compiler detail inside the compiler leaks into user space when you think them as the same thing.
In user space, conceptually they are different and always used in different scenarios (think UiBinder vs DOMImpl).

[*] If we don't require GWT.create for class replacement, anyone can replace any class for any purpose (e.g. browser compatibility, bug patching), this is way more useful to than mix and match.

On Sat, Aug 10, 2013 at 8:15 AM, Thomas Broyer <t.br...@gmail.com> wrote:
There aren't really two concepts: you can mix and match generate-with and replace-with for the same type, and/or switch from one to the other over time.

Actually, replace-with is only a shorthand for a generator returning a constant value (of a class that already exists).

John A. Tamplin

unread,
Aug 12, 2013, 1:16:06 AM8/12/13
to Google Web Toolkit Contributors
On Mon, Aug 12, 2013 at 1:13 AM, Goktug Gokdogan <gok...@google.com> wrote:
Even though the current form is pretty flexible and you can mix and match the two, it doesn't mean it makes sense to do so. I'm having hard time thinking about out a good use case that would make a single complex mix and match more appealing than having a separate group of class replacements and a codegen (AFAIK, there is not even single example in the GWT-SDK itself). Actually separating the two can result in something much more useful&powerful [*].

An example use-case would be implementing String.format when the format string is a compile-time constant.  I had a proof of concept mostly working for this, but it was going to require more surgery to the compiler than I was willing to do at the time.

--
John A. Tamplin

Goktug Gokdogan

unread,
Aug 12, 2013, 1:19:01 AM8/12/13
to google-web-toolkit-contributors
APT is missing mostly whole-world kind of informations in TypeOracle (e.g. getAllSubTypes) but perhaps this is also advantage and that is why it help the compiler to scale better :) Also looking at the usages of getAllSubTypes it is not like a major deal if we replace GWT-RPC with something that is more DTO centric.

I can't remember the discussion from the meet-up, I wonder if there were any other issues brought up there?

Goktug Gokdogan

unread,
Aug 12, 2013, 1:38:47 AM8/12/13
to google-web-toolkit-contributors
On Sat, Aug 10, 2013 at 10:28 AM, John A. Tamplin <j...@jaet.org> wrote:
On Fri, Aug 9, 2013 at 7:16 PM, Goktug Gokdogan <gok...@google.com> wrote:
I think in the long-run we should separate the two concepts that is being tackled by GWT.create today.

First purpose is the class replacement, especially used by permutations. I think this one should not have anything to do with GWT.create. We can do any class replacement in compiler without requiring a call to GWT.create. This is similar to super-sourcing and can be solved similar and perhaps together.

I don't see how it is similar to super-sourcing, as you need to dynamically select which class goes on there. For example, think about implementing GWT.create(SomeLocalizableSubclass).  There are hundreds of locales, and different classes are going to have different implementations so you have to make the substitution decision for each one of them separately.

Are you proposing to hook new Foo and substituting the class?  Where does the compiler get the knowledge to know which class to substitute?  I don't think you want to build all the knowledge of the ClientBundle generator into the compiler, for example.

I'm not proposing to get rid of the replace-with or generate-with.
I'm proposing to kill replace-with's association with GWT.create and codegen. 
 
 
Second purpose is for triggering generators and what most of the proposal are about.

As Roberto and perhaps others have been bringing up, it is best to follow regular java code generation practices in GWT.

That means for the long-term we can mostly rely on AnnotationProcessors.
There are many advantages of that:
  1. Not GWT only - continue sharing code with server (JRE), client(GWT) and mobile(Android).

You can use shared.GWT.create today in all those environments.

I can't use GWT.create today to generate code for server-side or Android. I can rewrite the same feature using reflection but that misses the point and also not always practical for Android.
 
 
  2. IDE support: IDE can trigger codegen (esp. for debugging)

My experience with this has been pretty poor, and running GWT with -gen is at least as useful.

--
John A. Tamplin

--

Goktug Gokdogan

unread,
Aug 12, 2013, 1:42:15 AM8/12/13
to google-web-toolkit-contributors
On Sat, Aug 10, 2013 at 11:18 AM, Brian Slesinsky <skyb...@google.com> wrote:

  2. IDE support: IDE can trigger codegen (esp. for debugging)

My experience with this has been pretty poor, and running GWT with -gen is at least as useful.

Also, Super Dev Mode gives you access to all the generated code. You can either use the browser's debugger with SourceMaps turned on (which also allows you to set breakpoints in generated code), or you can browse the source code directly on the codeserver.

It would be nice if we somehow got this working with an IDE, though.


I think this makes sense for client side although it would be better to see the code without running the app.
On the other hand we still have the problem with server-side and Android.

Goktug Gokdogan

unread,
Aug 12, 2013, 1:56:41 AM8/12/13
to google-web-toolkit-contributors
Today, even GWT generator developers are having trouble debugging generated code with -gen (just think GWTTestCase). It is not very practical for every day usage of end users.
I don't know how well APT support of IDEs are today but that's something that IDE's itself can improve upon and we can just share the benefit.


--

Goktug Gokdogan

unread,
Aug 12, 2013, 2:29:06 AM8/12/13
to google-web-toolkit-contributors
I didn't fully understand the example but it sounds like it requires way more than today's deferred binding so I'm not sure it is a good use case with replace-with/generate-with and static selectors. Perhaps it should be better done with something like "evaluate-with" instead. Actually, evaluate-with sounds interesting - I'll think about it :)
 
--
John A. Tamplin

John A. Tamplin

unread,
Aug 12, 2013, 2:42:43 AM8/12/13
to Google Web Toolkit Contributors
On Mon, Aug 12, 2013 at 2:29 AM, Goktug Gokdogan <gok...@google.com> wrote:
An example use-case would be implementing String.format when the format string is a compile-time constant.  I had a proof of concept mostly working for this, but it was going to require more surgery to the compiler than I was willing to do at the time.


I didn't fully understand the example but it sounds like it requires way more than today's deferred binding so I'm not sure it is a good use case with replace-with/generate-with and static selectors. Perhaps it should be better done with something like "evaluate-with" instead. Actually, evaluate-with sounds interesting - I'll think about it :)

I thought we were talking about potential improvements to GWT.create, so it doesn't have to be something that can be done with today's implementation.  Similar motivations were behind some proposals RayC made years ago as well.

--
John A. Tamplin

Goktug Gokdogan

unread,
Aug 12, 2013, 2:19:05 PM8/12/13
to google-web-toolkit-contributors
John, I put together a quick proposal for "evaluate-with" as a comment to the document. Please take a look.


--

Ray Cromwell

unread,
Aug 16, 2013, 2:27:19 AM8/16/13
to google-web-toolkit-contributors

My original motivation was like the String.format() case, but with GwtQuery's $() function, since GwtQuery supported compile-time CSS selector parsing, is was really tedious to add them to an interface when all you wanted was $(".foo > h1.title") or some such. Later, when doing GWT Exporter I noticed again code getting peppered with GWT.create() calls that were not type safe. Finally, after seeing repeating patterns in this, ranging from GWT RPC, to UiBinder, Editors, AutoBeans, Validators, etc I came to the conclusion that GWT.create()'s inability to be wrapped in a typed Java API and reliance on call-site inlining actually produced code smell -- it prevents the design of APIs and instead causes people to indulge in interface voodoo.

The reality is, I think people want to write code like $("css query") or String.format(fmt, args...) or Mockito.mock(SomeClass.class).

The only real wave I've seen this made manageable with minimal boilerplate is via the CDI stuff of Errai, but that kind of dependency injection I think is pretty heavyweight for what GWT users want to do. It's like imposing Guice/GIN on all GWT users.




--

Andrés Testi

unread,
Aug 20, 2013, 6:46:04 PM8/20/13
to google-web-tool...@googlegroups.com
As an alternative to what Goktug proposed about macros, we would have an equivalent to Scala macros (sorry for insisting with Scala :-) )

  @Macro(SumGenerator.class)
  Integer sum(Integer arg0, Integer arg1) {
    // We will never be here
    return null;
  }

  // rebind space
  class SumGenerator {

    Expr<Integer> sum(GeneratorContext ctx, TreeLogger logger, Arg<Integer> arg0, Arg<Integer> arg1) {

       if(arg0.isLiteral() && arg1.isLiteral()) {

         // If both arguments are literals, we sum they at compile time
         Integer result = arg0.getValue() + arg1.getValue();

         return ctx.compile("return {};", result);
       }

       // We return a runtime sum
       return ctx.compile("return {} + {};", arg0, arg1);
    }
  }

- Andrés
Reply all
Reply to author
Forward
0 new messages