On Sun, Apr 24, 2016 at 8:51 PM, Sven Meier <[email protected]> wrote:

> Hi Martin,
>
> that's quite nice to have these methods in IModel actually.
>
> Java 8 default methods to the rescue :)
>

The only method impl that bothers me is #flatMap().
I've made it non-lazy to be able to return the produced IModel<R>.
I have to see how other Monad impls do it.


>
> Regards
> Sven
>
>
>
> On 24.04.2016 17:20, Martin Grigorov wrote:
>
>> Hi,
>>
>> I've moved Matthias' code to IModel in branch monad-model (
>>
>> https://git1-us-west.apache.org/repos/asf?p=wicket.git;a=commitdiff;h=484132a8;hp=f2f0ba067e9cf3a4f31eb3c387d6244c3c06c44b
>> )
>> Just to see how it will look like.
>> And I think it is not bad at all!
>> By moving these methods to IModel we make them available to all impls.
>> Once
>> such method is called it effectively makes the model read-only, because a
>> new IModel is returned and IModel#setObject() already throws an exception.
>> If the application developer wants a read-write model then (s)he has to
>> use
>> #flatMap() and return a writeable model.
>>
>> The branch is just a playground!
>> I've touched one of the existing tests just because I was lazy to create a
>> new one.
>>
>>
>> Martin Grigorov
>> Wicket Training and Consulting
>> https://twitter.com/mtgrigorov
>>
>> On Sun, Apr 24, 2016 at 12:56 PM, Matthias Metzger <
>> [email protected]> wrote:
>>
>> 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