On Sun, Apr 24, 2016 at 10:44 PM, Martin Grigorov <[email protected]>
wrote:

> I've removed IModel from the type of the parameter of #apply():
> https://git1-us-west.apache.org/repos/asf?p=wicket.git;a=commitdiff;h=506ada45;hp=268bce97f173e5a2ee2f2f7d734a0c35c9ee960d
> Please let me know if the IModel is really needed for something.
>

Now I think there is no need of #apply() at all.
What use cases do you see for #apply() ?


>
> Martin Grigorov
> Wicket Training and Consulting
> https://twitter.com/mtgrigorov
>
> On Sun, Apr 24, 2016 at 10:34 PM, Martin Grigorov <[email protected]>
> wrote:
>
>> Unfortunately #flatMap() is still not what I'd like it to be.
>>
>> @Test
>> public void flatMap()
>> {
>>    IModel<String> heirModel = IModel.of(person).flatMap(person1 -> new
>> Model<String>() {
>>       @Override
>>       public String getObject()
>>       {
>>          return person1.getName() + " is my parent";
>>       }
>>    });
>>    assertThat(heirModel.getObject(), is(equalTo("John is my parent")));
>>
>>    String newValue = "New Value";
>>    heirModel.setObject(newValue);
>>    assertThat(heirModel.getObject(), is(equalTo(newValue)));   // << THIS
>> FAILS
>> }
>>
>> the new value is set on a *fresh* instance of "new Model". I.e. it goes
>> to /dev/null
>>
>> Martin Grigorov
>> Wicket Training and Consulting
>> https://twitter.com/mtgrigorov
>>
>> On Sun, Apr 24, 2016 at 9:14 PM, Martin Grigorov <[email protected]>
>> wrote:
>>
>>>
>>> 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