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