Proposal: Deprecate Builders
Daniel Zwolenski
zonski at gmail.com
Mon Mar 25 12:20:05 PDT 2013
I'm in a crappy internet cafe in peru so reading all of that was not the
easiest so apologies if I missed some stuff. A couple of things though:
1. FXML? It uses builders pretty heavily I believe and I'm pretty sure
anything I've written in JFX would instantly and dramatically break if they
dissapeared. I imagine there is also a code dependency between fxml code
and builders so removing it might be tricky?
2. This splitting out into separate JARs is a little along the lines of
jigsaw, could/should it not be used here (when is jigsaw happening?)
3. If we start splitting out jars we open up the door for something I would
have preffered in the first place. Move any non-core library out (e.g.
jfx-charts, jfx-fxml, etc). These are not JVM (i.e. operatin system) level
libraries in my opinion and would work much better as separate libraries.
Reduce the bloat (especially for mobile) and have less rigid constraints
than the JRE e.g. separate release cycles, ability to change/deprecate
stuff more like other libraries (spring, hibernate, etc), ability to use
other libraries (e.g. an xml parser or a math library).
This last point likely will be contentious but having these out in
something philosophically more like swingx would be better for everyone in
my opinion. It's the code the community can and probably want to evolve (as
opposed to media, rendering, 3d, etc) and there's no particular benefit to
it being in the JRE only costs involved. Doesn't mean Oracle can't
sanction/support/manage/contribute, etc.
On Mon, Mar 25, 2013 at 1:46 PM, Jonathan Giles
<jonathan.giles at oracle.com>wrote:
> I fall into the camp of never using builders in my projects, so I won't
> feel impacted by the move. However, I know a lot of people do use them, and
> I wonder whether another option is to supply the builders as a separate jar
> file for JavaFX 8.x as well. This 8.x builders.jar file could use the
> flattened structure and therefore be 'proper'. This file would be a
> separate library that developers can download and use, as is common in the
> Java world. The benefit is that people who don't use builders will never
> have to see them (or be impacted by their cost), whilst they are still
> available for the subset of people who do prefer their usage.
>
> Perhaps the concern is the extra work required to modify the *Builder
> generator, which I can't imagine is super trivial, but assuming it doesn't
> take a large amount of time then I think this is something to consider -
> assuming people feel strongly that builders should remain in some form.
>
> -- Jonathan
>
>
> On 26/03/2013 6:35 a.m., Richard Bair wrote:
>
>> We made a mistake. When we released JavaFX 2.0 we included a (large) set
>> of *Builder classes to provide a builder-pattern approach to building
>> JavaFX UIs. The builder-pattern approach provides several very nice
>> features:
>> - Ability to setup generic configuration once and "stamp out"
>> multiple copies
>> - Structured code style that closely approximates the "container
>> hierarchy" of the UI
>> - Strongly-typed "declarative" style programming
>>
>> The Builders did come at a cost. There are a lot of them, and if used,
>> require more class loading which slows down startup. When Pack200 is not
>> being used, they represent a sizable fraction of the code base. They
>> clutter up the JavaDoc (although this could be solved by having a "Builder"
>> section like there is an "Enum" section and "Interface" section).
>>
>> But all those advantages and costs were weighed and we concluded Builders
>> were worth it, and they went in. Based on the above, I would still conclude
>> that Builders are OK. However, it turns out our implementation has some
>> intractable problems with respect to binary compatibility.
>>
>> In order to ensure our Builders are always up-to-date with the latest API
>> added to the core classes, the Builders are auto-generated using an
>> annotation processor. Also, in order to keep the size of the builders small
>> relative to the rest of the platform, we employ complex use of generics in
>> order to allow the builders to inherit. That is, ControlBuilder extends
>> from ParentBuilder extends from NodeBuilder just as Control extends from
>> Parent extends from Node. But accomplishing this was no easy feat. Although
>> the "id(String)" method is defined on NodeBuilder, it must return a
>> ControlBuilder when used from the ControlBuilder. All of this was
>> accomplished using generics, and as it turns out, depended on two bugs in
>> JDK 6 and JDK 7 in order to work (although we didn't know it at the time).
>> Those bugs were fixed in JDK 8, and as a result, the builders no longer
>> work correctly for certain cases. Just about any option we take is going to
>> lead to a binary incompatibility in 8, however we find this unacceptable.
>> If we cannot avoid it, then whatever we choice we make for 8 had better be
>> a final solution -- not something we will later decide we need to tweak
>> further.
>>
>> And this is what puts us in a tight spot. After having painfully looked
>> over all of the alternatives, it seems to come down to this:
>> a) Flatten the builder hierarchy so that ControlBuilder extends
>> Object the same as ParentBuilder would and all other Builders.
>> b) Stop using builders. Phase them out in a controlled manner.
>>
>> Option (a) works because we remove all generics from the equation. There
>> are some 73 or so methods on NodeBuilder. These would be redefined on the
>> Builder for each class that extends from Node. This solution works by
>> solving the root problem -- generic use in builder subclassing scenarios.
>> This solution however changes the cost/benefit analysis for Builders,
>> because now they would then comprise a much larger fraction of the overall
>> platform size. And this runs at cross purposes with embedded use cases.
>>
>> Option (b) works by removing Builders from the scenario entirely. Because
>> this would be a *huge* breaking change, it would have to be managed
>> carefully in a way that, in fact, won't break anybody (for at least several
>> years). To implement this option, we would:
>> 1) Add @Deprecate to all Builders with a URL in the description
>> to a page describing the change and how to migrate
>> 2) Stop auto-generating builders. We'd take whatever we had in
>> the latest 2.x line and reuse them as-is.
>> - This means that as new API is added to the platform,
>> the builders wouldn't be updated to match
>> 3) Remove the Builders from the Java 8 JavaDoc
>> 4) Split the builders into a separate jar from jfxrt.jar. It
>> would also be on the java.ext.libs path so that it is automatically picked
>> up so that people are not broken when running FX 2.x apps on 8.x without
>> modification. They'd still work.
>> 5) Provide a download link to the fx2-builders.jar containing all
>> these builders.
>> 6) Encourage people to use fx2-builders.jar instead of relying on
>> builders being on the class path by default
>> 7) In Java 9, remove the builders from the class path (this is
>> several years down the road)
>>
>> This proposal is essentially saying that the fix to make Builders work
>> correctly reduces the value of the builders to the point where they just
>> aren't worth it, and when considering Mobile / Embedded use cases, the
>> extra cost of the builders is prohibitive. It also is based on the theory
>> that the Builders are not being used by everybody, and so many people would
>> not be negatively impacted but rather only positively impacted by no longer
>> paying for the additional cost in bytes for the builders. It also
>> recognizes that people who *are* using the builders and *do* like the
>> programming style (including Jasper and many of our own) will see a loss of
>> functionality that they have grown to like.
>>
>> The other thing to bear in mind is that most of the benefits of Builders
>> don't have to come from Builders -- there are alternatives. For example,
>> the 'Ability to setup generic configuration once and "stamp out" multiple
>> copies' benefit can also be achieved by helper methods. The 'Structured
>> code style that closely approximates the "container hierarchy" of the UI'
>> advantage can be accomplished using FXML instead, or by using this pattern
>> (which creates a boat-load of inner classes so it has its own problems):
>>
>> // The first set of braces defines it as an anonymous subclass, the
>> second set as an initializer
>> Group g = new Group() {{
>> getChildren().add(new Button() {{
>> setText("Hello");
>> }});
>> }};
>>
>> Another option which we've discussed a bit is whether we could use
>> lambda's to do configuration in a builder-like style in Java 8, somewhat
>> like Groovy does. So for example:
>>
>> Group g = new Group(gg -> {
>> gg.getChildren().addAll(new Button(b -> {
>> b.setText("Hello");
>> });
>> });
>>
>> This approach doesn't generate the mass of anonymous inner classes that
>> the other double-brace approach does, but accomplishes the same basic job
>> of using builders for (more or less) declarative construction of a
>> container-hierarchy in code.
>>
>> So this is the long and the short of it. Eva can follow up with an
>> in-depth post about the binary compatibility concerns if you wish. My
>> proposal after having weighed the options is to phase out the Builders by
>> deprecating them in 8 and removing them from the class path in 9. I believe
>> that FXML or Lambda's or alternative languages all provide other avenues
>> for achieving the same goals as builders but without the additional cost in
>> byte codes or classes.
>>
>> We have some cases where SceneBuilder is presently relying on the
>> Builders, and we'd have to provide alternatives for that functionality it
>> is presently using (such as annotations for constructor arguments).
>>
>> Richard
>>
>
>
>
More information about the openjfx-dev
mailing list