core icon indicating copy to clipboard operation
core copied to clipboard

LazyModel - Type-safety for root object

Open ronaldtm opened this issue 11 years ago • 5 comments

LazyModel is type-safe regarding the model object (last getter), but not regarding the root object (what we pass to the from() method). Thus, the bind() method receives Object, and it is not possible to know what kind of object a model can be bound to without reading the code that created the base model.

Suggestion: make LazyModel have two type parameters (LazyModel<R,T>), and provide some way to specify (and ideally statically check) the type of R when creating the model object. Maybe add Class<R> to the model() method:

LazyModel<Person,Address> model = LazyModel.model(Person.class, LazyModel.from(Person.class).getAddress());

This will inevitably break backward compatibility, though. Not sure if it will be able to be implemented until wicket/wicketstuff's 7.x release.

ronaldtm avatar Sep 05 '13 18:09 ronaldtm

#bind() wasn't part of the first release, and without it there's no need for an additional type parameter.

Note that when creating a LazyModel, there's no way to reliably check the target type. We could change #model() as follows:

public static <S,R> LazyModel<S,R> model(R result);

But both of the following statements would work (although the second one is wrong)

LazyModel<A, B> model = model(from(a).getB());
LazyModel<C, B> model = model(from(a).getB());

So I'm not sure this change is really worth it.

svenmeier avatar Sep 05 '13 19:09 svenmeier

I suggested to add a new type parameter to the class, not switch from the return type to the root target type.

This want this mainly because I almost only use static pre-initialized unbound models through my code, due the documented performance hit, and I sometimes have to re-read the model declaration to be sure I'm binding it to the right object.

static final LazyModel<A,B> UNBOUND_MODEL = LazyModel.model(A.class, LazyModel.from(A.class).getB());
...
LazyModel<A,B> boundModel = UNBOUND_MODEL.bind(a); //would not compile if 'a' is not of type A
IModel<B> model = boundModel;

Note the A.class added parameter to the model() method. This wouldn't be completely type-safe (since you could pass A.class to the model() method and C.class to the from() method), but the client code would.

ronaldtm avatar Sep 05 '13 19:09 ronaldtm

This wouldn't be completely type-safe

That's the point I wanted to make.

... but the client code would.

Correct.

svenmeier avatar Sep 06 '13 07:09 svenmeier

Not being type-safe at the declaration code isn't a big problem, because you can easily verify if the types match (both are in the same line). And I guess LazyModel.model() could also check if the type passed to it matches the object passed to the from() method. Not in compile-time, but since these unbound models are likely to be declared as static-final attributes, the code would fail at load-time, I mean, fail as fast as runtime fail-fast goes.

ronaldtm avatar Sep 06 '13 14:09 ronaldtm

I've just tried it out and the additional type parameter seems to do no harm.

But the following is quite ugly IMHO:

LazyModel.model(A.class, LazyModel.from(A.class).getB());

svenmeier avatar Sep 06 '13 19:09 svenmeier