Feedback for records: Accessors name() vs. getName()

Roman Elizarov elizarov at gmail.com
Wed Aug 26 12:13:09 UTC 2020


Hello,

Let me add my 5 cents to the accessor naming thread from the standpoint of
various JVM languages (EL, Groovy, Kotlin, etc). I do not recall this
specific aspect of the issue being raised before, but since I was not
following it closely, I'm sorry if it was already discussed. I will also
propose one more potential solution for consideration that does not involve
any kind of getXxx naming convention. For the record (pun intended), I do
represent the Kotlin language design team, but I have a strong reason to
believe that the same conundrum is going to be faced by designers of many
JVM languages that support properties in their syntax. I cannot possibly
provide the full list of potentially affected languages here and the
representative subset I've picked is totally arbitrary and subjective on my
part, it is not intended to diminish the contribution of any other JVM
languages.

>> 2. Unified expression language (EL) in JSP, JSF

>> --------------------------------------------------------------
>> Web expression language will look quite weird as well (address() method
>> versus customer and city properties):

> Again, there's no reason why EL can't treat record component accessors
> the same way as methods who happen to be named g-e-t-something.  And
> there's  no reason why the () would be needed; it's just that they're
> not caught up with the language yet.

There is, in fact, a very big reason, why languages with properties rely on
the getXxx naming convention. Consider the following Java interface, as a
trivial example.

// the original version
public interface TimeService {
    Instant getCurrentTime();
    ServerInfo getTimeServerInfo();
    Instant synchronizeTimeWithServer();
}

This interface follows a well-established convention that side-effect-free
methods are named using the verb "get", while other business methods use
other domain-specific verbs. You can find this pattern followed all over
various JDK APIs (with some exceptions, of course) and in many enterprise
applications. This is a chief reason for a number of JVM languages to
piggy-back onto this convention to distinguish methods that could be
syntactically represented as a property like "timeService.currentTime" and
those methods that, despite having no parameters, are conceptually
inappropriate to be available in the syntactic form of a property, without
a programmer explicitly writing some sort of method invocation expression
like "timeService.synchronizeTimeWithServer()" (mind the brackets) or using
them in a method-invocation context (as it happens in EL).

Now consider a record TimeConfigSnapshot(Instant currentTime, ServerInfo
timeServerInfo). So far, so good. It is not a major problem for any JVM
language with properties to recognize that records are, by definition, pure
data containers and that all their components should be treated like
properties allowing a "timeConfig.currentTime" syntax without an explicit
method call.

However, let us see what happens over time with the design of Java
applications that use records. What if there is a business-domain need to
extract a common interface between a TimeService and a TimeConfigSnapshot
record since both of them essentially provide a pair of "currentTime" and
"timeServerInfo"? Now, the understandable desire to avoid extra boilerplate
would likely result in the introduction of the following kind of interface
which is automatically implemented by the TimeConfigSnapshot record without
additional code.

public interface TimeConfig {
    Instant currentTime();
    ServerInfo timeServerInfo();
}

The desire to keep the original TimeService interface compliant with this
newly introduced TimeConfig interface will call for its refactoring to
rename its methods according to the naming convention of the record
component accessor methods.

// the refactored post-record version
public interface TimeService extends TimeConfig {
    Instant currentTime();
    ServerInfo timeServerInfo();
    Instant synchronizeTimeWithServer();
}

Now, that looks very confusing, even from a Java programmer's standpoint,
since there is a common practice to start a method name with a verb. It is
even more confusing from the standpoint of any property-supporting JVM
language as there is now no clear way to tell which methods of the
TimeService interface are conceptually properties and which are not.

A potential solution that I can throw onto the table is to introduce some
sort of a standard JVM attribute or an annotation to explicitly mark
methods that correspond to the record component accessor methods and by
which the automatically-generated record component accessors are marked.
Tools will help here with the learning curve. When one goes to extract an
interface out of TimeConfigSnapshot record, the tools will make sure to
carry forth the corresponding annotation (attribute), producing something
like this (an appropriate name is TBD):

public interface TimeConfig {
    @__ComponentAccessor Instant currentTime();
    @__ComponentAccessor ServerInfo timeServerInfo();
}

This annotation or attribute will be especially helpful when carried forth
onto the larger interface like TimeService and will serve as a clue both to
the reader of this interface and to the various JVM languages and tools
that those methods are intended to be simple accessors to the underlying
data, something that was historically expressed by the "get" verb in the
name.

Technically, Java itself does not have to standardize this kind of
annotation or attribute. An annotation to tag those accessor/property
methods can and likely will be introduced as a part of those JVM language
runtimes that need it. However, this will have a negative effect on the JVM
ecosystem as a whole as those various annotations will end up being
incompatible with each other. So, please consider this as a part of the
Java records design effort.

Sincerely,
Roman Elizarov


More information about the amber-dev mailing list