Hi,

thanks for your comments!


>> whether those transformations should be done by a Model or
>> it would be better to be done by Functions and finally a Model
>> would consume the result

> my thoughts exactly: Chaining of functions is a broader topic. Note how
> ReadOnlyModel and LambdaColumn have identical #map() functions.


> Furthermore Java Function objects already support chaining with #andThen().
> The Java compiler just doesn't allow calling methods on a method reference:

> // doesn't work
> IModel<String> streetModel = LambdaModel.of(target,
> Person::getAdress.andThen(Address::getStreet));

I agree with both of you. The 'first' method is actually something Java 8 is 
totally missing in my opinion, which is one reason for my ideas. The other one 
being potential null values in the above, which we could rule out using 
Optional:

LambdaModel.of(target, p -> 
Optional.ofNullable(p).map(Person::getAddress).map(Address::getStreet).orElse("n/a"));

Maybe this is a better way to deal with this sort of chaining, because it's 
actually the same approach for the 'LambdaColumn' and uses  mechanisms, which 
are more general. I think one could even make an argument to create a getter 
for this case. The 'apply' could then be done in the following way:

LambdaModel.of(target, p -> Optional.ofNullable(p).
  map(Person::getName).
  map(name -> house.getObject().apply(name)).
  orElse("n/a"));


> - if this functionality should be in a model then in which class?
> -- AbstractReadOnlyModel is deprecated. Maybe we should un-deprecate it ?!
> -- the name "ReadOnlyModel" doesn't tell me what nice functionality I
> could expect from it. But on the side all these methods should be provided
> only by a read-only model. Or not? I see they can easily be put in IModel
> class, but then the developer should be careful with the usage of
> #setObject()


Despite the above, I'll still answer this concern:
You are right. The naming is absolutely terrible and I have been struggling 
with a good name not involving all the Haskell stuff I have been taking 
inspiration from. At the moment I would tend to call it MappableModel<T>. In 
light of the 8.x changes, I would let it implement IModel<T> - so no need for 
un-deprecating AbstractReadOnlyModel<T>. This was just because I have been 
playing around with 7.x. Yes, ReadOnlyModel and/or LoadableDetachableModel and 
also maybe a MappableColumn. Basically everything which mostly reads.

I have been tinkering with a method '#toIModel(BiConsumer<T, U> setter)', 
transforming the MappableModel to an IModel. That comes with some non-obvious 
caveats however.

Have a nice rest of the day,

Matthias




----- Ursprüngliche Message -----
Von: Sven Meier <[email protected]>
An: [email protected]
Gesendet: 12:23 Sonntag, 24.April 2016
Betreff: Re: Further Lambda Model ideas

Hi,

> whether those transformations should be done by a Model or
> it would be better to be done by Functions and finally a Model
> would consume the result

my thoughts exactly: Chaining of functions is a broader topic. Note how 
ReadOnlyModel and LambdaColumn have identical #map() functions.

Furthermore Java Function objects already support chaining with #andThen().
The Java compiler just doesn't allow calling methods on a method reference:

     // doesn't work
     IModel<String> streetModel = LambdaModel.of(target, 
Person::getAdress.andThen(Address::getStreet));

You have to use a method call to get an actual function object first:

     // this does work
     IModel<String> streetModel = LambdaModel.of(target, 
first(Person::getAdress).andThen(Address::getStreet));

     private <T1, T2> WicketFunction<T1, T2> first(WicketFunction<T1, 
T2> func) {
         return func;
     }

For this to work we have to add an additional method for serialization 
into WicketFunction though:

     // specialization of the super method for serializable functions
     default <V> WicketFunction<T, V> andThen(WicketFunction<? super R, 
? extends V> after)
     {
         Objects.requireNonNull(after);
         return (T t) -> after.apply(apply(t));
     }

Have fun
Sven


On 24.04.2016 11:34, Martin Grigorov wrote:
> On Sun, Apr 24, 2016 at 11:16 AM, Martin Grigorov <[email protected]>
> wrote:
>
>> Hi,
>>
>> I like the functionality provided by ReadOnlyModel!
>> I have two questions/doubts:
>> - whether those transformations should be done by a Model or it would be
>> better to be done by Functions and finally a Model would consume the result
>> - if this functionality should be in a model then in which class?
>> -- AbstractReadOnlyModel is deprecated. Maybe we should un-deprecate it ?!
>> -- the name "ReadOnlyModel" doesn't tell me what nice functionality I
>> could expect from it. But on the side all these methods should be provided
>> only by a read-only model. Or not? I see they can easily be put in IModel
>> class, but then the developer should be careful with the usage of
>> #setObject()
>>
>> I think a better solution would be a read-write Model that uses
>> composition of functions internally for all the transformations.
>> #setObject() will manipulate the model's object. #getObject() will apply
>> the model object to the composed function to get the final result.
>>
> This won't work. The mapping cannot be in the same IModel, a new IModel
> should be returned.
>
>
>>
>> Martin Grigorov
>> Wicket Training and Consulting
>> https://twitter.com/mtgrigorov
>>
>> On Fri, Apr 22, 2016 at 10:52 PM, Matthias Metzger <
>> [email protected]> wrote:
>>
>>> Hi,
>>>
>>>
>>> thanks to all of you for the interest! I just added some examples to the
>>> README of my repository and implemented an alternative to/enhanced the
>>> LambdaColumn. Hope this makes your life a little easier. If there is
>>> anything else I can do for that matter, just hit me up.
>>>
>>>
>>> @Carl-Eric: I am very keen to see what you'll come up with. Mapping over
>>> everything with a <T> was the best I could think of, without resorting to
>>> reflection. :D
>>>
>>> Regards,
>>> Matthias
>>>
>>>
>>> ________________________________
>>> Von: Carl-Eric Menzel <[email protected]>
>>> An: [email protected]
>>> Gesendet: 10:10 Freitag, 22.April 2016
>>> Betreff: Re: Further Lambda Model ideas
>>>
>>>
>>> Hi Matthias,
>>>
>>> interesting ideas, thank you for sharing! I'm going to have a closer
>>> look either this weekend or next (a bit busy right now). Currently I'm
>>> working on some Java 8 helpers for Wicket 7, similar to the LambdaModel
>>> thing currently in WicketStuff. I'm doing that mostly to just play
>>> around with some ideas but also because I'm not entirely happy with the
>>> WicketStuff LambdaModel - basically I'm exploring to see whether I can
>>> come up with something I like better.
>>>
>>> Carl-Eric
>>>
>>>
>>> On Thu, 21 Apr 2016 20:19:52 +0000 (UTC)
>>> Matthias Metzger <[email protected]> wrote:
>>>
>>>> Hello everyone,
>>>> I just saw yesterday, that the IModel became/will become a
>>>> @FunctionalInterface in Wicket 8 and was very happy about it. I am
>>>> also very happy about the ongoing implementations and discussions
>>>> around lambda usage in Wicket, because it simplifies a lot of code.
>>>> Now, one thing I have been working on, is implementing some of the
>>>> now known methods of Stream<T> for a AbstractReadOnlyModel and also
>>>> for other things - like columns. I have not seen such discussions on
>>>> here, please forgive me if I missed that. If it has indeed not been
>>>> discussed and you find the idea useful, you can take a look at an
>>>> implementation in the following repository:
>>>>
>>> https://github.com/noobymatze/lambdawicket-model/blob/master/src/main/java/com/github/noobymatze/lambdawicket/model/ReadOnlyModel.java
>>>> What might we be able to do with that?
>>>> Consider a Person containing an Address, containing a Street with a
>>>> name. Now I want to display the name of the street. How would I go
>>>> about that?new Label("streetName", () ->
>>>> person.getAddress().getStreet().getName()); This is one approach, but
>>>> it completely ignores the possibility of null values and a default
>>>> value for such cases. I could wrap the above in an Optional or create
>>>> a method in the Person class like 'Optional<String> getStreetName()
>>>> {...}'.
>>>>
>>>> With the proposed ReadOnlyModel I could also do it in the following
>>>> way: new Label("streetName", ReadOnlyModel.of(person).
>>>> map(Person::getAddress).  map(Address::getStreet).
>>>> map(Street::getName).  orElse("n/a")); But that's not all. Imagine we
>>>> would need to dynamically truncate the streetName based on user
>>>> input: IModel<WicketFunction<String, String>> truncate = () -> str ->
>>>> str.length() > 10 ? str.substring(0, 10) + "..." : str;
>>>> IModel<String> truncatedStreetName = ReadOnlyModel.of(person).
>>>> map(Person::getAddress).    map(Address::getStreet).
>>>> map(Street::getName).    apply(truncate).    orElse("n/a"); Now we
>>>> could switch the truncate Model using a
>>>> DropDownChoice<WicketFunction<String, String>> or by just setting the
>>>> contained function somewhere.truncate.setObject(str ->
>>>> str.substring(0, 20));
>>>>
>>>> The whole approach is - if I am not mistaken - heavier on memory,
>>>> because instead of one IModel<String> we now have 5 or 6 Models, that
>>>> cannot be garbage collected, because they are all needed to perform
>>>> the computation.
>>>>
>>>> This doesn't apply for mapping over an IColumn though, because it
>>>> doesn't need to rely on the laziness, like the ReadOnlyModel does
>>>> (otherwise a change in truncate wouldn't mean a change in the final
>>>> value), so:new LambdaColumn(of("Name"), Person::getAddress).
>>>> map(Address::getStreet).  map(Street::getName).  orElse("n/a"));
>>>> would create 4 new instances of the LambdaColumn, but 3 of them could
>>>> be gc'd more or less the second they were created - like I said, if I
>>>> am not mistaken. If this is at all an approach you think might be
>>>> useful, I would be happy to provide the implementation of the
>>>> LambdaColumn. Otherwise just ignore my message. :) Have a nice
>>>> day,Matthias
>>

Reply via email to