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