No, these methods have a very clear and complete API. IModel is a functional 
interface and these methods allow you to use lambda's directly as models. 

Emond

On woensdag 8 februari 2017 15:36:12 CET Andrew Geery wrote:
> Do we want to do a similar thing for factory methods around models, such as
> LoadableDetachableModel#of?
> 
> Andrew
> 
> On Wed, Feb 8, 2017 at 2:53 PM, Andrea Del Bene <[email protected]>
> 
> wrote:
> > I think we all (more or less :-) ) agree about moving factory methods away
> > from components. I don't think we need a dedicated and experimental module
> > for them. I'd rather move them to class Lamdas and, if we need it, we can
> > deprecate them in future.
> > 
> > On 08/02/2017 17:24, Sven Meier wrote:
> >> I like Edmond's suggestion:
> >> 
> >> "We can also move them all to a factory class and place this class in
> >> experimental.
> >> That way we can do with it whatever we like."
> >> 
> >> So we have a place to refer questioners to when they are looking for
> >> these factory methods.
> >> 
> >> Regards
> >> Sven
> >> 
> >> On 08.02.2017 16:55, Martin Grigorov wrote:
> >>> https://github.com/apache/wicket/pull/211 :-)
> >>> Let's drop them all!
> >>> 
> >>> Martin Grigorov
> >>> Wicket Training and Consulting
> >>> https://twitter.com/mtgrigorov
> >>> 
> >>> On Wed, Feb 8, 2017 at 4:34 PM, Emond Papegaaij <
> >>> [email protected]>
> >>> wrote:
> >>> 
> >>> I can live with the following:
> >>>> Factory methodes should:
> >>>>   * accept exactly 1 lambda (and possibly an id)
> >>>>   * be a static method on the component or behavior they create
> >>>>   * be given meaningfull names
> >>>>   * be limited to at most 1 or 2 per type
> >>>>   * not pass the instance they create to the lambda
> >>>> 
> >>>> This would mean all methods should be moved from Lambdas and duplicates
> >>>> like
> >>>> AjaxLink.onClick should be removed.
> >>>> 
> >>>> Still, I like the idea to remove them all better. We can also move them
> >>>> all to
> >>>> a factory class and place this class in experimental. That way we can
> >>>> do
> >>>> with
> >>>> it whatever we like.
> >>>> 
> >>>> Best regards,
> >>>> Emond
> >>>> 
> >>>> On woensdag 8 februari 2017 16:20:59 CET Andrea Del Bene wrote:
> >>>>> I agree with Martijn, especially when he warns about the huge risk we
> >>>> 
> >>>> take
> >>>> 
> >>>>> overusing lambdas and making API inconsistent. But I don't agree to
> >>>>> take
> >>>>> such an extreme choice like removing EVERY factory methods. Like
> >>>>> Martin
> >>>>> suggested these methods can be very useful when they are limited to
> >>>>> the
> >>>>> very basic functionality of a component (link onClick for a Link).
> >>>>> More in general I would say that a lambda factory method should not
> >>>>> take
> >>>>> more than one lambda as parameter.
> >>>>> 
> >>>>> On Wed, Feb 8, 2017 at 3:17 PM, Martin Grigorov <[email protected]>
> >>>>> 
> >>>>> wrote:
> >>>>>> On Wed, Feb 8, 2017 at 3:08 PM, Martijn Dashorst <
> >>>>>> [email protected]
> >>>>>> 
> >>>>>> wrote:
> >>>>>>> There are many things to consider when designing an API. Usability
> >>>>>>> of
> >>>>>>> the API, readability of the resulting code, maintenance burden for
> >>>>>> 
> >>>>>> the
> >>>>> 
> >>>>> core developers, but also performance, memory consumption and
> >>>>> 
> >>>>>>> serialization overhead.
> >>>>>>> 
> >>>>>>> Adding lifecycle fields to Component for any extension point will
> >>>>>>> dramatically increase the footprint of any Wicket application.
> >>>>>>> Lambda's are not a free lunch and add considerable memory and
> >>>>>>> serialization overhead to Java code.
> >>>>>>> 
> >>>>>>> Wicket is not only used for small demos of how fancy lambda's can
> >>>>>>> be,
> >>>>>>> but also for applications where 10's of thousands or even millions
> >>>>>>> of
> >>>>>>> users concurrently use the application. Adding a byte to the
> >>>>>> 
> >>>>>> footprint
> >>>>> 
> >>>>> of Component can increase the memory footprint of the application
> >>>>> 
> >>>>>> with
> >>>>> 
> >>>>> 10's of megabytes.
> >>>>> 
> >>>>>>> So yes we have considered adding these things but find the problem
> >>>>>>> they solve not worth the extra footprint. Furthermore the clarity of
> >>>>>>> the code does not increase when you have 3 or 4 methods that need
> >>>>>>> implementing, but those add considerable memory footprint (8 bytes
> >>>>>> 
> >>>>>> per
> >>>>> 
> >>>>> reference when unused, much more when used) when provided through
> >>>>> 
> >>>>>>> lambdas.
> >>>>>>> 
> >>>>>>> Calculation
> >>>>>>> 
> >>>>>>> Say you have 1 million components in memory. Say we add lambda's for
> >>>>>>> the primary life cycle events and enabled/visible flags. This is:
> >>>>>>> 
> >>>>>>> - onInitialize
> >>>>>>> - onEvent
> >>>>>>> - onReAdd
> >>>>>>> - onRemove
> >>>>>>> - onRender
> >>>>>>> - onConfigure
> >>>>>>> - onBeforeRender
> >>>>>>> - onBeforeRenderChildren
> >>>>>>> - onComponentTag
> >>>>>>> - onComponentTagBody
> >>>>>>> - onAfterRender
> >>>>>>> - onAfterRenderChildren
> >>>>>>> - onDetach
> >>>>>>> - isVisible
> >>>>>>> - isEnabled
> >>>>>>> 
> >>>>>>> This is without onFoo methods available in Link, Form etc. 15
> >>>>>>> references that may or may not be used. 15*8 = 120 bytes per
> >>>>>>> component. Now we have added 120MB to an application without anyone
> >>>>>>> even using the functionality. The cost is considerably higher when
> >>>>>>> actually using the lambda's. See the measurements I did for my talk
> >>>>>> 
> >>>>>> at
> >>>>> 
> >>>>> ApacheCon 2016 in Sevilla [1]
> >>>>> 
> >>>>>>> Of course we can try to minimize the memory footprint, and store the
> >>>>>>> event references in the data bucket of Component and store only
> >>>>>>> those
> >>>>>>> events that are actually used. But this will add an O(n^2) for every
> >>>>>>> request because we need to loop through the data array at each life
> >>>>>>> cycle event to find if there's a registered reference, and if so use
> >>>>>>> that. While for a single request this is not too big an issue, it
> >>>>>> 
> >>>>>> adds
> >>>>> 
> >>>>> up when you consider that this must be done for millions of
> >>>>> 
> >>>>>> components
> >>>>> 
> >>>>> for all lifecycle events.
> >>>>> 
> >>>>>>> API design
> >>>>>>> 
> >>>>>>> So let's consider the case when we were to add setters for lambda's
> >>>>>> 
> >>>>>> to
> >>>>> 
> >>>>> Component et al. We can't remove the old way of subclassing because
> >>>>> 
> >>>>>>> that would break the world. Thus we have two ways of how to add an
> >>>>>>> onConfigure or onDetach event to a component. Which one is canon? We
> >>>>>>> already have at least 3 ways to determine whether a component is
> >>>>>>> visible or not:
> >>>>>>> 
> >>>>>>> - call setVisible (static visibility)
> >>>>>>> - override isVisible
> >>>>>>> - setVisibilityAllowed
> >>>>>>> - override onConfigure() and call setVisible
> >>>>>>> 
> >>>>>>> This has harmed the Wicket API in my opinion and is a result of us
> >>>>>> 
> >>>>>> not
> >>>>> 
> >>>>> understanding at the time how, when and how often visibility needed
> >>>>> 
> >>>>>> to
> >>>>> 
> >>>>> be evaluated.
> >>>>> 
> >>>>>>> Adding setters for lambda's would at least double the API surface.
> >>>>>>> Furthermore you need to take into account that these setters can't
> >>>>>>> be
> >>>>>>> hidden by subclasses. So when you use a component that has
> >>>>>> 
> >>>>>> onConfigure
> >>>>> 
> >>>>> overridden, what happens when you setOnConfigure()?
> >>>>> 
> >>>>>>> public class FooPanel extends Panel {
> >>>>>>> 
> >>>>>>>      public FooPanel(String id) { super(id); }
> >>>>>>>      
> >>>>>>>      @Override
> >>>>>>>      protected void onConfigure() {
> >>>>>>>      
> >>>>>>>          super.onConfigure();
> >>>>>>>          // if something set visiblity
> >>>>>>>      
> >>>>>>>      }
> >>>>>>> 
> >>>>>>> }
> >>>>>>> 
> >>>>>>> add(new FooPanel("foo").setOnConfigure(() -> { ... do something
> >>>>>>> completely different ... });
> >>>>>>> 
> >>>>>>> So which one should prevail? the lambda or the overridden method? Ah
> >>>>>> 
> >>>>>> I
> >>>>> 
> >>>>> hear you say "rewrite the FooPanel such that it doesn't override
> >>>>> 
> >>>>>>> onConfigure". But then we have 2 onConfigure lambda's set:
> >>>>>>> 
> >>>>>>> public class FooPanel extends Panel {
> >>>>>>> 
> >>>>>>>      public FooPanel(String id) {
> >>>>>>>      
> >>>>>>>          super(id);
> >>>>>>>          setOnConfigure(() -> {
> >>>>>>>          
> >>>>>>>              /* if something set visibility */
> >>>>>>>          
> >>>>>>>          });
> >>>>>>>      
> >>>>>>>      }
> >>>>>>> 
> >>>>>>> }
> >>>>>>> 
> >>>>>>> add(new FooPanel("foo").setOnConfigure(() -> { ... do something
> >>>>>>> completely different ... });
> >>>>>>> 
> >>>>>>> So which one should prevail? Well, call both! OK, this means that we
> >>>>>>> need to store both lambdas. So each lifecycle event lambda store
> >>>>>> 
> >>>>>> needs
> >>>>> 
> >>>>> to be a data structure that can hold multiple lambdas, which
> >>>>> 
> >>>>>> increases
> >>>>> 
> >>>>> the memory footprint even further. Then we have to issue of which
> >>>>> 
> >>>>>>> lambda to call first. The one added in the constructor of FooPanel,
> >>>>>> 
> >>>>>> or
> >>>>> 
> >>>>> the one that was set after construction?
> >>>>> 
> >>>>>>> This doesn't even take into account the semantics of for example the
> >>>>>>> onInitialize lifecycle event, which states that it is called when a
> >>>>>>> component is added to the hierarchy of a page (i.e. a parent-path
> >>>>>>> exists to the page). A setOnInitialize can be invoked at any moment
> >>>>>>> after construction. Therefore its semantics become even muddier than
> >>>>>>> they already are:
> >>>>>>> 
> >>>>>>> Label label = new Label(...);
> >>>>>>> add(label);
> >>>>>>> 
> >>>>>>> label.setOnInitialize(() -> { ... });
> >>>>>>> 
> >>>>>>> OK, so we don't add a lambda possibility for onInitialize (queue the
> >>>>>>> pull requests).
> >>>>>>> 
> >>>>>>> Another thing to consider is that a component builder currently can
> >>>>>>> decide to close off particular events from being overridden or
> >>>>>>> modified. For example:
> >>>>>>> 
> >>>>>>> public class FooPanel extends Panel {
> >>>>>>> 
> >>>>>>>      public FooPanel(String id) { super(id); }
> >>>>>>>      
> >>>>>>>      /** No longer overridable */
> >>>>>>>      @Override
> >>>>>>>      protected final void onConfigure() {
> >>>>>>>      
> >>>>>>>          super.onConfigure();
> >>>>>>>          // if something set visiblity
> >>>>>>>      
> >>>>>>>      }
> >>>>>>> 
> >>>>>>> }
> >>>>>>> 
> >>>>>>> The component designer found it necessary to remove the ability to
> >>>>>>> override onConfigure().
> >>>>>>> 
> >>>>>>> However you can't remove the ability to add/set lambda's from
> >>>>>>> Component. These methods need to be public for them to be usable,
> >>>>>>> and
> >>>>>>> you can't hide those methods.
> >>>>>>> 
> >>>>>>> Summary
> >>>>>>> 
> >>>>>>> Lambdas are a great tool but should be used wisely and we should be
> >>>>>>> careful about our API and take good design into consideration
> >>>>>>> instead
> >>>>>>> of just papering our API with lambdas. There are many aspects to
> >>>>>>> consider, not just the fact that you can write 2 lines of
> >>>>>>> non-executable code less.
> >>>>>> 
> >>>>>> YES!
> >>>>>> That's why I think the current factories we have is the best we can
> >>>>> 
> >>>>> give -
> >>>>> 
> >>>>> they are very handy for (my?!) the trivial case and they cannot be
> >>>>> 
> >>>>>> extended
> >>>>>> further with more functionality, it is just not practical to add more
> >>>>> 
> >>>>> to
> >>>>> 
> >>>>> them.
> >>>>> 
> >>>>>> For more inspiration take a look at other UI libs like
> >>>>> 
> >>>>> JavaFX/TornadoFX,
> >>>>> 
> >>>>> Vaadin 8, Scalatags/Kotlinx.html, ...
> >>>>> 
> >>>>>> Martijn
> >>>>>> 
> >>>>>>> [1] http://www.slideshare.net/dashorst/whats-up-with-wicket-> >>>>>> 
> >>>>>> 8-and-java-8
> >>>>> 
> >>>>> On Wed, Feb 8, 2017 at 11:45 AM, Andrew Geery <
> >>>>> 
> >>>>>> [email protected]>
> >>>>> 
> >>>>> wrote:
> >>>>>>>> Rather than using static factory methods, would we ever consider
> >>>>>>> 
> >>>>>>> pushing
> >>>>>> 
> >>>>>> the lambdas into the component classes themselves?
> >>>>>> 
> >>>>>>>> For example, if we did this with the Button class, the change would
> >>>>>>>> be:
> >>>>>>>> 
> >>>>>>>> - Add two private fields, SerializableConsumer<Button>
> >>>>>>> 
> >>>>>>> submitHandler,
> >>>>> 
> >>>>> errorHandler
> >>>>> 
> >>>>>>>> - Add "setters" for these fields -- e.g., Button
> >>>>>>>> submitHandler(SerializableConsumer<Button> submitHandler)
> >>>>>>>> - Modify the onSubmit() and onError() methods to call the handler
> >>>>>>> 
> >>>>>>> methods
> >>>>>> 
> >>>>>> if they are not null
> >>>>>> 
> >>>>>>>> A call would be something like:
> >>>>>>>> 
> >>>>>>>> add(new Button("button").submitHandler(b ->
> >>>>>>> 
> >>>>>>> System.out.println("clicked"));
> >>>>>>> 
> >>>>>>> Obviously, it is still possible to sub-class Button and override
> >>>>>>> 
> >>>>>>>> onSubmit(), so existing code will continue to work. However, for
> >>>>>>> 
> >>>>>>> code
> >>>>> 
> >>>>> going forward, it should be much less needed and, in my opinion,
> >>>>> 
> >>>>>>> much
> >>>>> 
> >>>>> clearer.
> >>>>> 
> >>>>>>>> Another advantage to doing things this way is that sub-classes
> >>>>>>> 
> >>>>>>> inherit
> >>>>> 
> >>>>> these methods and there is no need to add static factory methods
> >>>>> 
> >>>>>>> for
> >>>>> 
> >>>>> every
> >>>>> 
> >>>>>>> sub-class (sub-classes of AjaxButton would be a better example of
> >>>>>>> 
> >>>>>>> this).
> >>>>>> 
> >>>>>> Thanks
> >>>>>> 
> >>>>>>>> Andrew
> >>>>>>>> 
> >>>>>>>> On Wed, Feb 8, 2017 at 3:42 AM, Martijn Dashorst <
> >>>>>>> 
> >>>>>>> [email protected]
> >>>>>>> 
> >>>>>>> wrote:
> >>>>>>>>> It is that your trivial use case is not my trivial use case and
> >>>>>>>> 
> >>>>>>>> that
> >>>>> 
> >>>>> we will end up with a 100,000 trivial use cases.
> >>>>> 
> >>>>>>>>> And no, confusion is not the big issue (though for
> >>>>>>>> 
> >>>>>>>> onsubmit+onerror
> >>>>> 
> >>>>> it
> >>>>> 
> >>>>>>>>> is) but creating a good API is hard. It takes time and
> >>>>>>>> 
> >>>>>>>> understanding.
> >>>>> 
> >>>>> Minimizing lines of code is not the only metric for a good API.
> >>>>> 
> >>>>>>>>> Just as using inheritance/annotations/generics for everything is
> >>>>>>>> 
> >>>>>>>> bad,
> >>>>> 
> >>>>> introducing factory methods everywhere will not age well.
> >>>>> 
> >>>>>>>>> These methods are trivial for anyone to implement and should we
> >>>>>>>> 
> >>>>>>>> reach
> >>>>> 
> >>>>> the conclusion that we actually need the factory methods in core,
> >>>>> 
> >>>>>>>> it
> >>>>> 
> >>>>> is trivial to refactor them towards the Wicket supplied factories.
> >>>>> 
> >>>>>>>>> Are the factory methods in the way? Yes they are, because once we
> >>>>>>>> 
> >>>>>>>> add
> >>>>> 
> >>>>> them, we can't evolve them without adding many more (introduce
> >>>>> 
> >>>>>>>> bloat)
> >>>>> 
> >>>>> or having to wait until a new major release.
> >>>>> 
> >>>>>>>>> Martijn
> >>>>>>>>> 
> >>>>>>>>> 
> >>>>>>>>> 
> >>>>>>>>> 
> >>>>>>>>> On Tue, Feb 7, 2017 at 11:40 PM, Martin Grigorov <
> >>>>>>>> 
> >>>>>>>> [email protected]>
> >>>>>> 
> >>>>>> wrote:
> >>>>>>>>>> Hi,
> >>>>>>>>>> 
> >>>>>>>>>> These methods are factories for the trivial use cases where
> >>>>>>>>> 
> >>>>>>>>> nothing
> >>>>> 
> >>>>> else
> >>>>> 
> >>>>>>> needs to be overridden but the action method (methods, when
> >>>>>>> 
> >>>>>>>>> there
> >>>>> 
> >>>>> is
> >>>>> 
> >>>>>>>>>> onError()). They do help to reduce the verbosity!
> >>>>>>>>>> There are plenty of those cases. You can see many usages in
> >>>>>>>>>> wicket-examples. I have used such methods from
> >>>>>>>>> 
> >>>>>>>>> wicketstuff-scala in
> >>>>> 
> >>>>> one
> >>>>> 
> >>>>>>> of
> >>>>>>> 
> >>>>>>>>> my projects in the past and I use similar ones in a project with
> >>>>>>>>> 
> >>>>>>>>> Kotlin
> >>>>>>> 
> >>>>>>> now.
> >>>>>>> 
> >>>>>>>>> A builder that provides methods like onConfigure(),
> >>>>>>>>> 
> >>>>>>>>> onComponentTag(),
> >>>>>> 
> >>>>>> onDetach(), ... would look really strange!
> >>>>>> 
> >>>>>>>>>> Who will use it instead of just creating a (inner) class ?!
> >>>>>>>>>> 
> >>>>>>>>>> But if those factory methods confuse core developers then they
> >>>>>>>>> 
> >>>>>>>>> will
> >>>>> 
> >>>>> be
> >>>>> 
> >>>>>> even
> >>>>>> 
> >>>>>>>>> more confusing to normal users :-/
> >>>>>>>>> 
> >>>>>>>>>> 0 from me.
> >>>>>>>>>> 
> >>>>>>>>>> Martin Grigorov
> >>>>>>>>>> Wicket Training and Consulting
> >>>>>>>>>> https://twitter.com/mtgrigorov
> >>>>>>>>>> 
> >>>>>>>>>> On Tue, Feb 7, 2017 at 5:07 PM, Martijn Dashorst <
> >>>>>>>>> 
> >>>>>>>>> [email protected]
> >>>>>>>>> 
> >>>>>>>>> wrote:
> >>>>>>>>>>> All,
> >>>>>>>>>>> 
> >>>>>>>>>>> I want to remove all component factory methods that are added
> >>>>>>>>>> 
> >>>>>>>>>> for
> >>>>> 
> >>>>> lambda's.
> >>>>> 
> >>>>>>>>> My reasoning is that:
> >>>>>>>>>>> - removing them in 8.x (x > 0) is impossible
> >>>>>>>>>>> - adding them in 8.x (x > 0) is trivial
> >>>>>>>>>>> - we currently don't have a way to know what good idioms are
> >>>>>>>>>>> - having these factories push (new) developers to use the wrong
> >>>>>>>>>> 
> >>>>>>>>>> idiom
> >>>>>> 
> >>>>>> - factory methods don't allow for additional overriding, thus a
> >>>>>> 
> >>>>>>>>>>> combinatorial explosion of API
> >>>>>>>>>>> - I tend to think that builders are better suited as component
> >>>>>>>>>> 
> >>>>>>>>>> factories
> >>>>>>> 
> >>>>>>> Because it is trivial to re-introduce these factories or their
> >>>>>>> 
> >>>>>>>>>>> replacements at a later time, I propose to remove them now and
> >>>>>>>>>> 
> >>>>>>>>>> figure
> >>>>>> 
> >>>>>> out in our actual applications what works, and what doesn't. I
> >>>>>> 
> >>>>>>>>>>> also
> >>>>>>>>>>> think that just doing the conversion from W7 to W8 isn't
> >>>>>>>>>> 
> >>>>>>>>>> enough to
> >>>>> 
> >>>>> figure this out.
> >>>>> 
> >>>>>>>>>>> Example 1:
> >>>>>>>>>>> 
> >>>>>>>>>>> Button.java has two factory methods:
> >>>>>>>>>>> 
> >>>>>>>>>>> Button#onSubmit(String, SerializableConsumer<Button>), and
> >>>>>>>>>>> Button#onSubmit(String, SerializableConsumer<Button>,
> >>>>>>>>>>> SerializableConsumer<Button>)
> >>>>>>>>>>> 
> >>>>>>>>>>> It is not possible to see without resorting to parameter
> >>>>>>>>>> 
> >>>>>>>>>> naming,
> >>>>> 
> >>>>> hovering etc to see which functionality is bound by which
> >>>>> 
> >>>>>>>>>> parameter.
> >>>>>> 
> >>>>>> I
> >>>>>> 
> >>>>>>> find the naming confusing: onSubmit and onSubmit.
> >>>>>>> 
> >>>>>>>>>>> Example 2:
> >>>>>>>>>>> 
> >>>>>>>>>>> Behavior.java has two factory methods:
> >>>>>>>>>>> 
> >>>>>>>>>>> Behavior onTag(SerializableBiConsumer<Component,
> >>>>>>>>>> 
> >>>>>>>>>> ComponentTag>)
> >>>>> 
> >>>>> Behavior onAttribute(String name,
> >>>>> 
> >>>>>>>>>>> SerializableFunction<String, CharSequence> onAttribute)
> >>>>>>>>>>> 
> >>>>>>>>>>> These achieve basically the same functionality, but other life
> >>>>>>>>>> 
> >>>>>>>>>> cycle
> >>>>>> 
> >>>>>> events of Behavior don't have factory methods. NOR should they.
> >>>>>> 
> >>>>>>>>>>> Example 3:
> >>>>>>>>>>> 
> >>>>>>>>>>> Lambdas.java has many factory methods, most of which are better
> >>>>>>>>>>> implemented by just using an anonymous inner class. For
> >>>>>>>>>> 
> >>>>>>>>>> example,
> >>>>> 
> >>>>> Lambdas.link: often times you need to override onconfigure or
> >>>>> 
> >>>>>>>>>>> oncomponenttag as well as onclick.
> >>>>>>>>>>> 
> >>>>>>>>>>> Martijn
> >>>>>>>>>> 
> >>>>>>>>>> --
> >>>>>>>>> 
> >>>>>>>>> Become a Wicket expert, learn from the best:
> >>>>>>>> http://wicketinaction.com
> >>>>>> 
> >>>>>> --
> >>>>>> 
> >>>>>>> Become a Wicket expert, learn from the best:
> >>>>>> http://wicketinaction.com


Reply via email to