Java Enhancement Proposal: Field Accessors

Julian Waters tanksherman27 at gmail.com
Thu Mar 24 02:29:00 UTC 2022


Hi all,


It would be appreciated if I could get feedback and refinements

on the current Amber JEP draft.


Thanks and have a great day! :)


best regards,

Julian


Summary
-------

Enhance Java with language level field accessors.

Accessors provide an easy way to define logic for setting

and retrieving field values in what would otherwise be a

tedious process of writing multiple methods (with potential

overloads)

Goals
-----

It is intended for this new feature to work with full

compatibility with existing manually defined methods,

as well as with inheritance and subclass overriding,

and to provide a clean way to define accessors with

different signatures.


Motivation
----------

>From JEP-395: "It is a common complaint that

"Java is too verbose" or has "too much ceremony"."


Currently, if one wishes to have private fields with

public methods to modify them, it is required to write

at least one getter and setter. In the worst case, it

is required to write multiple copies of the exact same method

if there need to be multiple overloads. This eventually

becomes overly tedious or error prone, and a common desire

is that Java had cleaner syntax for such field access. It

may be tempting to ask why direct field modification is not

then used instead, but accessing a field through methods

allows custom logic to be executed, which is particularly

useful for state checking and possibly returning or setting

a different value if the situation call for it. Other

languages, such as Kotlin and C#, have dedicated syntax

for such "getters and setters", but their approach only

allows for one such set to be specified, and no extra

parameters other than the built in ones are allowed. We

should not abandon the flexibility overloads in Java

provide for the sake of such a feature, so we'll need an

approach that combines the compactness of other such

languages with the more Java-esque method style for full

flexibility and ease of use.


Description
-----------


The current proposal proposes the syntax for field

accessors as follows:


// Getters have the same name as the field
// Setters have the name of set<PascalCase name of the field>

private long field = 0 {
    // Getter, leave semicolons after return to define a getter
without running any custom logic, or a block if custom logic is
required
    return;

    // Getter that executes custom logic
    // If no return is specified in the getter, it will implicitly
return the field bound to it
    // after executing the body
    return { /*Code here*/ }


    // Getter that explicitly returns a value using a return statement
in the body
    // Note that "this" refers to the field and not the containing class
    // To explicitly access the containing class, use KlassName.this
    return { return this; };

    // Getter that returns another field instead of this one. Note
that KlassName.this is
    // not required to access other fields in the class; It serves the
same purpose as
    // regular usages of "this": To differentiate fields defined in
the class itself and
    // local variables

    // Note that the other field MUST have the same type

    // as the one the accessor is bound to
    return { return KlassName.this.otherField }

    // Getter overloaded with custom signature
    // Note: No getter or setter can share the same signature
    return(Klass klass) {}


    // Return random literal

    return { return 42L; }


    // Accessors can call their own overloads too, if

    // required

    // If an accessor calls its own overload, the implicit

// setting or getting is disabled.

    return { field(); }

    // Setter, leave as is to implicitly set field to value without
any custom logic
    // Note that the type and name do not need to be set, the type is
already inferred
    // and the name is not needed unless it has to be referred to in a
body with custom
    // logic
    new;

    // Setter that executes body before assigning a value to the field
    // Like Getters, Setters execute the body first before setting the
field, unless the order
    // is customized by setting "this" to another value explicitly
    new { /*Code*/ }


    // Setter that accepts parameters. Method signature when being
called will be (valueToSet, ...)
    new(KlassName otherType) {}


    // Accessors can call their own overloads too, if

// desired

// If an accessor calls its own overload, the implicit

// setting or getting is disabled.

 new { setField(5); }

// Setter with access to the value being sent to set the field // Type is
automatically inferred, but can be set if desired for whatever reason
new(value) -> {} // Setter with both access to the new value and more
parameters new(value) -> (KlassName otherType) {} // Setter that explicitly
sets the field // Normally the field is set implicitly if nothing is
assigned to "this" in the body new(value) -> { this = value; } // Setter
with a return type. By default, setters are void // Both setters and
getters can be marked as final in the same manner with the "final" //
keyword char new { return 'c'; } } // To override the getter/setter in
subclasses, if possible

// Eg not marked as final

// Type is immediately inferred, but can be explicitly specified
before the identifier if
// there are other fields with the same name but different type
// This is only possible if those fields have getters or setters
super field {
    // Syntax is the same as above
}

// Note that overriding getters or setters defined by

// this new syntax can be done in the typical
// way, if desired, and vice versa
@Override
public long field() {  /*Logic*/ }


@Override
public void setField(long value) {  /*Logic*/ }


The above are all ultimately implemented as normal methods,

making supporting them relatively easy and requiring

little change to javac as a whole, and also means that

any accessor can be overridden by subclasses with regular

methods with the correct name and signature, as shown above

(Unless marked final)


Currently, there is no proposal for static fields. This can

hopefully be worked on as discussion around this JEP progresses


Alternatives
------------

The Lombok project has annotations that can be added

to fields to automatically generate getters and setters,

however this would require developers to install a third

party library, when native language support would be much

more efficient to work with. Additionally, Lombok's field

annotations can only generate one set of methods and do not

allow for overloads, making it much less flexible than the

currently proposed syntax. Alternatively, we could continue

to stick to Java's traditional way of directly writing

methods, but developers often find such an approach rather

tedious, and the amount of boilerplate required with this

approach can make it ultimately more error prone.


Risks and Assumptions
---------------------

This JEP assumes that developers have prior knowledge of

accessors, and will not have any issues making their code

work with the new language feature.


More information about the amber-dev mailing list