Fluent getters without fluent setters and withers (@Accessors)

1,287 views
Skip to first unread message

Tomasz Linkowski

unread,
Aug 30, 2017, 6:53:42 AM8/30/17
to Project Lombok

Problem

I would very much like to have fluent getters (fluent in the sense "no prefix") but simultaneously have classic (prefixed) setters and withers.

 

AFAIK there's no way to do it using the @Accessors annotation in its current form.

 

Example

What I'd like to get:

  • getter

    car.color()

  • and:
    • either setter:

      car.setColor(Color.BLUE)

    • or wither:

      car.withColor(Color.BLUE)

 

What I get with

@Accessors(fluent=true)

  • getter:

    car.color()

  • setter/wither

    car.color(Color.BLUE)

 

Rationale

As you can see, the main problem is that setters become indistinguishable from withers. I consider this a very serious problem so I never use @Accessors when I need a wither.

 

But another problem is that such setter/wither doesn't tell me what it does:

  • I don't need to "hear" what a getter does because I don't consider car.color() as "getting" the color - I consider it as merely accessing it so it "reads" fine.
  • But car.color(Color.BLUE) is always non-intuitive to me, no matter whether it's a setter or a wither. It's because it's not immediately obvious whether it returns a Color or does something else.

So the "set" prefix (saying "I change the field's value") and the "with" prefix (saying "I clone the object, I set the field's value in the clone, and return the clone") are crucial to me.

 

Ideas

I have the following ideas about how to solve this issue in a backward-compatible manner:

  1. My favorite because it would be easiest to be used:
    Add prefix attribute to @Getter annotation (plus config lombok.getter.prefix) whose default value would be "get".
    PROs:
    - it's more versatile than simple fluent attribute
    - it might help with some non-standard getters (e.g. with boolean getters where "are" instead of "is" prefix is required, like allLinesVerified => areAllLinesVerified())
    CONs:
    - yet another attribute in @Getter annotation
    @Accessors already has prefix attribute, and it has a different meaning (it concerns field prefixes). However, maybe methodPrefix or getterPrefix name would do?
  2. Very similar to the above:
    Add fluent attribute to @Getter annotation (plus config lombok.getter.fluent = true|false) whose default value would be false.
    PROs:
    - simpler than the above and consistent with fluent in @Accessors
    CONs:
    - yet another attribute in @Getter annotation
    - if someone's (like mine) understanding of "fluent" entails "chained", @Getter(fluent = true) might sound a bit misleading.
  3. Entirely different approach:
    Add AccessorTarget[] targets attribute to @Accessors:

    enum AccessorTarget { GETTER, SETTER, WITHER }

    and that (by default) would be set to all of them. Of course, it should also come with lombok.accessors.targets config option (which would support += and -=, like lombok.accessors.prefix).
    PROs:
    - safer (because can be added to an experimental @Accessors instead of non-experimental @Getter)
    - quite clear design
    CONs:
    - more verbose in non-config usage (even more than current @Accessors)
    - might be problematic if people want to place more than one annotation to separately configure different targets

Martin Grajcar

unread,
Aug 30, 2017, 11:48:27 PM8/30/17
to project...@googlegroups.com
As you can see, the main problem is that setters become indistinguishable from withers. I consider this a very serious problem so I never use @Accessors when I need a wither.

That's strange. My withers do always have the with prefix. I'm using
lombok.accessors.fluent=true
lombok.accessors.chain=true
in the configuration, but I've just tried adding @Accessors and nothing changed.

Tomasz Linkowski

unread,
Sep 7, 2017, 8:38:27 AM9/7/17
to Project Lombok
I tried to reproduce the behavior with lombok.accessors fluent and chain flags set to true. Here's what I got:

As you can see, only when fluent=false, the wither has a prefix. And if I delete lombok.config, the wither also has a prefix if there's no @Accessors.

Please, let me know how you achieved it that your withers have a prefix in presence of fluent=true.

Regards,
Tomasz Linkowski

Martin Grajcar

unread,
Sep 7, 2017, 12:54:53 PM9/7/17
to project...@googlegroups.com
On Thu, Sep 7, 2017 at 2:38 PM, 'Tomasz Linkowski' via Project Lombok <project...@googlegroups.com> wrote:
I tried to reproduce the behavior with lombok.accessors fluent and chain flags set to true.

That's what I always use.
 
Here's what I got:

As you can see, only when fluent=false, the wither has a prefix. And if I delete lombok.config, the wither also has a prefix if there's no @Accessors.

I've just added @Accessors(fluent=true, chain=true) and recompiled the project, nothing changes.
 
Please, let me know how you achieved it that your withers have a prefix in presence of fluent=true.

I did nothing. AFAIK that's the standard behavior and I've never heard otherwise.

I guess, you're using Idea (just guessing; I'm not and can't try it at the moment) and this may be a bug in the plugin? Please try with Eclipse and/or javac and report the bug (including the lombok version, lombok plugin version, your IDE including version, etc) on either https://github.com/rzwitserloot/lombok/issues or https://github.com/mplushnikov/lombok-intellij-plugin/issues. Only the case without prefix is interesting.
  • I don't need to "hear" what a getter does because I don't consider car.color() as "getting" the color - I consider it as merely accessing it so it "reads" fine.
  • But car.color(Color.BLUE) is always non-intuitive to me, no matter whether it's a setter or a wither. It's because it's not immediately obvious whether it returns a Color or does something else.
For withers, it's a bug. But I guess, I could like setters having a prefix and getters having none. OTOH lombok has already tons of features and it's rather improbable this one will get in anytime soon. Anyway, I'm not the one to decide (and those who are seem to be pretty busy).

Tomasz Linkowski

unread,
Sep 8, 2017, 4:53:02 AM9/8/17
to Project Lombok
Maaartin G,

Thank you very much :) You were right about the wither - using javac, I could not compile the code that tried to use abc("") instead of withAbc(""). So it's a bug in lombok-intellij-plugin - I reported it.

As for setters having no prefix - I'm glad you'd like them too. But since the withers behave as expected, I too am under impression that this feature (unfortunately) seems too minuscule to be added by the lombok developers.

Regards!
Tomasz Linkowski

Bennett Lynch

unread,
Oct 3, 2017, 1:03:05 PM10/3/17
to Project Lombok
+1 for wanting support for this feature.

I've grown fond of the Netty project's clean coding style, which uses no-prefix getters, but with prefixed setters:
http://netty.io/wiki/new-and-noteworthy-in-4.0.html#wiki-h2-2

This isn't achievable by Lombok today. @Accessors should be configurable by @Getter or @Setter.
Reply all
Reply to author
Forward
0 new messages