I've been working on a prototype inspired by Ray Cromwell's proposal for 
@GwtCreate parameters, borrowing some ideas from Scala implicit macros. I 
apologize for not to post this in the "Possible GWT.create() Improvements" 
thread, but this message is too long to be only a comment. 
You can check my patch at https://gwt-review.googlesource.com/4110. This 
prototype has passed many JUnit tests cases and works fine. Devmode also 
works.
This proposal differs from Ray's original idea in that @GwtCreate is a 
parameter annotation instead of a method annotation. Later I will justify 
this decision.
This new proposal consists on rewriting methods adding a trailing implicit 
parameter of type GwtCreateFactory for each parameter annotated with 
@GwtCreate. GwtCreateFactory is a hidden interface used by the compiler:

  interface GwtCreateFactory {
    <T> T create();
  }

When the compiler finds a code-gen method like

  Foo createFoo(@GwtCreate final Class<? extends Foo> fooType) {
    return GWT.create(fooType);
  }

it is rewritten as

  Foo createFoo(final Class<? extends Foo> type, GwtCreateFactory 
fooType$factory) {
    return fooType$factory.create();
  }

IMPORTANT: 
---- The @GwtCreate parameter requires to be final.
---- This proposal doesn't require constant evaluation expression. The 
final modifier is required to disable non reproductible side effects.

At method call site, an invocation like

  Foo foo = createFoo(SubFoo.class);

is rewritten as

  class SubFoo$GwtCreateFactory implements GwtCreateFactory {
    @Override public <T> T create() {
      return GWT.create(SubFoo.class);
    }    
  }

  Foo foo = createFoo(SubFoo.class, new SubFoo$GwtCreateFactory());

Just like Scala implicit parameters, @GwtCreate can fight against type 
erasure and subtyping

  interface FooCreator {

    <T extends Foo> T create(@GwtCreate Class<T> fooType);  
  }

  class FooCreatorImpl extends FooCreator {

    <T extends Foo> T create(@GwtCreate final Class<T> fooType) {
      return GWT.create(fooType);
    }
  }

code-gen constructors are supported too

  class CreateByConstructor<T extends Foo> {
  
    final T instance;
 
    public  CreateByConstructor(@GwtCreate final Class<T> fooType) {
      instance = GWT.create(fooType);
    }
  }

Again, as in Scala implicit parameters, nesting is allowed

  class Foo {}
  class SubFoo extends Foo {}

  <F extends Foo> F createFoo(@GwtCreate final Class<F> fooType) {
    return GWT.create(fooType);
  }

  <S extends SubFoo> S createSubFoo(@GwtCreate final Class<S> subFooType) {
    return createFoo(subFooType);
  }

The decision to locate @GwtCreate on parameters was taken to support mixed 
code-gen methods

  <F extends Foo, B extends Bar>
  void fooBarCreator(@GwtCreate final Class<F> fooType, @GwtCreate final 
Class<B> barType) {
    foo = GWT.create(fooType);
    bar = GWT.create(barType);
  }

Note that the @GwtCreate class parameters aren't replaced by 
GwtCreateFactory as was originally suggested by Ray Cromwell. This provides 
access to actual parameters.

  Class<T> storedType;
  T instance;

  void createFoo(@GwtCreate final Class<T> type) {
    storedType = type;
    instance = GWT.create(type);  
  }

* Further improvements:

  1) Support for explicit generators

    @GwtCreate(generator = FooGenerator.class)

    We should forbid assignation between parameters that differs in 
@GwtCreate signature

      Foo createFoo(@GwtCreate(generator = FooGen.class) final Class<? 
extends Foo>) {...}

      // This will fail
      Foo forbiddenNesting(@GwtCreate(generator = BarGen.class) final 
Class<? extends Foo> fooType) {
        return createFoo(fooType);
      }

  2) Multiple parameters for GWT.create() by means of @GwtCreate.Param

      <U, O> UiBinder<U, O> createBinder(
            @GwtCreate(generator = UiBinGen.class) final Class<U> uiType, 
            @GwtCreate.Param final Class<O> ownerType) {

         return GWT.create(uiType, ownerType);
      }

    @GwtCreate.Params must respect the same kind of signature rules than 
@GwtCreate, and a strict order of invocation

      // Good ordering
      Foo createFoo(
            @GwtCreate final Class<? extends Foo> fooType,
            @GwtCreate.Param final Class<?> arg1,
            @GwtCreate.Param final Class<?> arg2) {  
        return GWT.create(fooType, arg1, arg2);
      }

      // Bad ordering, this will fail
      Foo createFoo(
          @GwtCreate final Class<? extends Foo> fooType,
          @GwtCreate.Param final Class<?> arg1,
          @GwtCreate.Param final Class<?> arg2) { 

        return GWT.create(fooType, arg2, arg1);
      }
 
    To allow mixed multiple code-gen parameters, we would bind main 
parameters by name

      <F extends Foo, B extends Bar>
      void mixedMultiple(
          @GwtCreate final Class<F> fooType, 
          @GwtCreate.Param("fooType") final Class<?> fooArg,
          @GwtCreate final Class<B> barType, 
          @GwtCreate.Param("barType") final Class<?> barArg)

  3) Support for GWT.create(this.getClass()) ? not exactly, but...

    Explicits generators can eliminate the issue of the unique generator 
per class hierarchy. An aditional boolean parameter for @GwtCreate would 
mitigate the code size issue

      abstract class UiBinderComposite extends UiBinderComposite {

        public UiBinderComposite() {
          UiBinder<Widget, UiBinderComposite> binder = 
createBinder(getClass());
        }

        private static UiBinder<Widget, UiBinderComposite>
            createBinder(@GwtCreate(        
                    // The explicit generator knows when to stop the code 
generation
                    generator = UiBinderCompositeGenerator.class,

                    // this.getClass() is disallowed by default.
                    allowsThisClass = true) 
                final Class<? extends UiBinderComposite> type) {

          return GWT.create(type);
        }
      }

    Only API authors should treat with GWT.create(). API users should stay 
isolated by means of code-gen methods.


I can formalize all of these in a document if you agree. 

Thanks for your attention!

- Andrés

-- 
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-contributors+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to