PROPOSAL: Auto-assignment Parameters

james lowden jl0235 at yahoo.com
Wed Mar 25 12:04:53 PDT 2009


I don't like the multiple annotations approach as it removes the convenience of being able to easily get the default magic behaviors via one modifier.  There's certainly precedent for this in the language; applying the "synchronized" keyword to a method or block of code gives you a default set of "magic" concurrency behaviors which under the hood are in fact somewhat complex.

My only concern with it as stands is that "data" in class declarations is a keyword, and presumably is a valid identifier everywhere else; I'd rather see something that wasn't a valid Java identifier used to denote this behavior.  I wouldn't mind seeing "default" used this way (to imply desirable "default" behavior), as in:

default public class Foo {

  private int x;
  private String blah;

}

generates all the default getters/setters/equals/hashcode/constructor.

-JL-


--- On Wed, 3/25/09, Lawrence Kesteloot <lk at teamten.com> wrote:

> From: Lawrence Kesteloot <lk at teamten.com>
> Subject: Re: PROPOSAL: Auto-assignment Parameters
> To: coin-dev at openjdk.java.net
> Date: Wednesday, March 25, 2009, 1:25 PM
> Reinier,
> 
> The idea of adding a context-sensitive keyword creeps me
> out. Also
> this is doing a lot of magic based on a single keyword. Can
> you tell,
> at a glance, what the keyword is doing? How much is
> generated? What
> are the (complex) rules for auto-generating a constructor?
> 
> I would prefer a more explicit approach, driven by
> annotations. If we
> feel like boilerplate is annoying to write and bug-prone,
> then we
> could have a java.lang.gen package with various annotations
> for
> automatically generating code. Something like:
> 
> @GenerateFullConstructor
> @GenerateEqualsAndHashCode
> @GenerateToString(JsonToStringGenerator.class)
> public class Foo {
>     @GenerateGetter
>     private final int x;
>     @GenerateGetter
>     private final int y;
>     @GenerateGetter
>     private final String foo;
> }
> 
> Then it's explicit, each annotation can have parameters
> to modify its
> behavior, and people can pick and choose what they need.
> There's no
> magic about skipping the generation of toString if
> you've implemented
> it.
> 
> Here's an example of useful parameters for such
> annotations: many
> people (myself included) like to prefix fields with
> something. I use
> "m" (mFoo), but others use an underscore, and
> some both (m_foo). You'd
> want the GenerateGetter annotation to be flexible about
> that. My code
> would look like this:
> 
>     @GenerateGetter(prefix = "m")
>     private final String mFoo;
> 
> Your "data" keyword would preclude this, forcing
> me to either drop my
> (company-mandated) coding standard for data classes, or
> have getters
> like "getMFoo()".
> 
> With GenerateEqualsAndHashCode you might want to skip some
> fields. You
> might want to skip fields for GenerateToString also (e.g.,
> password
> fields, or super long strings).
> 
> Lawrence
> 
> 
> On Wed, Mar 25, 2009 at 9:59 AM, Reinier Zwitserloot
> <reinier at zwitserloot.com> wrote:
> > There's no reference for auto-POJOs anywhere, but
> this should allow
> > you to write up all you need:
> >
> > 1. 'data' is a context sensitive keyword that
> is legal on classes. The
> > 'data' keyword will add a number of members to
> the class.
> >
> > 2. For each field, a getter is generated, according to
> the beanspec
> > (getFoo() or isFoo()). if the field is not final, a
> setter is
> > generated, according to beanspec (setFoo()), and the
> field is
> > considered a property of the data class, unless it is
> transient. If
> > the field is public, the getter (and, if not final,
> the setter), is
> > not generated. For all generated getters/setters, if
> the getter/setter
> > is already in the class, or already defined (that is;
> not abstract) in
> > any supertype, then the getter/setter is not
> generated. protected and
> > visible package protected members from supertypes are
> also included
> > both for generating setters/getters and for
> hashCode/equals/toString/
> > clone (upcoming).
> >
> > 3. hashCode() and equals(): Existence of the
> hashCode() or equals()
> > method in any supertype is not relevant (obviously;
> all objects have
> > them!)
> >
> > 3a. If only one of hashCode() or equals() is present,
> a warning is
> > generated and neither hashCode() or equals() is
> auto-generated. The
> > warning basically explains that overriding one but not
> the other is a
> > bug.
> >
> > 3b. If both hashCode() and equals() are present,
> nothing happens.
> >
> > 3c. If neither is present, a hashCode() and equals()
> method are
> > generated. These involve all properties (non-transient
> visible
> > fields). equals() is defined by:
> >
> >  3c1: First check if the other object is of the exact
> same class as
> > ourselves; if not, false. If null, false.
> >  3c2: For each primitive property, check via == if
> they are equal. If
> > any isn't, false.
> >  3c3: For each object property, call its .equals().
> If they aren't,
> > false.
> >  3c4: return true.
> >
> > for hashCode(), do whatever eclipse does out of the
> box to auto-
> > generate hashCode() methods. It basically looks like:
> >
> > final int PRIME = 31;
> > int result = 1;
> > for ( each field ) result = result*31 +
> field.hashCode();
> > return result;
> >
> > Where hashCode() is generated in obvious fashion for
> all primitives
> > (xor the upper and lower bits of longs together,
> convert floats and
> > doubles to long/intbits and use that,
> chars/bytes/ints/shorts's
> > hashCode is their own value, booleans are translated
> to 11/17. 'null'
> > becomes 3.
> >
> > 4. *IF* all fields are private, and *IF* all fields
> are final, *AND*
> > the class does not contain any explicit constructors,
> *AND* the class
> > has a no-args super constructor, then a constructor is
> generated that
> > includes all fields, in order of definition, which
> simply assigns them
> > to the fields. visible properties from supertypes
> aren't included.
> >
> > 5. A toString() method is generated, if not already
> present in the
> > type, which produces a string like so:
> "MyClassName [field1=value,
> > field2=value]", for all properties. (so,
> non-visible fields from
> > supertypes and transient fields are skipped).
> >
> > 6 (optional). Each generated member gets a @Generated
> annotation,
> > which is a new annotation (
> java.lang.annotations.Generated ). These
> > are @Documented and @Retention.RUNTIME.
> >
> >
> > Is it viable for coin? I'll write it up if so.
> >
> >  --Reinier Zwitserloot
> >
> >
> >
> > On Mar 25, 2009, at 14:41, james lowden wrote:
> >
> >>
> >> I'd like to see both.
>  Auto-getters/setters/equals/etc. would be
> >> really, really nice, but it would also be valuable
> to have a way of
> >> specifying a variety of different constructors to
> generate, which
> >> Mark's proposal would allow for.  Example:
> >>
> >> public data class Foo {
> >>      private final int x;
> >>      private final int y;
> >>      private final String foo;
> >>
> >>      public Foo (this.x) {}
> >>
> >>      public Foo (this.foo, this.y) {}
> >> }
> >>
> >>
> >> (I eliminated the types from the automagical
> constructors, as they
> >> can be inferred by the compiler.)
> >>
> >> This would generate all three getters and setters,
> equals (),
> >> hashcode (), a general constructor taking in all 3
> fields, and two
> >> additional constructors, one taking in just int x,
> and one taking in
> >> both String foo and int y.
> >>
> >> Reinier--is there a copy of your original proposal
> for auto-POJOs
> >> somewhere?
> >>
> >> -JL-
> >>
> >>
> >>> From: Reinier Zwitserloot
> <reinier at zwitserloot.com>
> >>> Subject: Re: PROPOSAL: Auto-assignment
> Parameters
> >>> To: "Mark Mahieu"
> <markmahieu at googlemail.com>
> >>> Cc: coin-dev at openjdk.java.net
> >>> Date: Tuesday, March 24, 2009, 8:34 PM
> >>> I like where this is going, but I'd rather
> see a bigger
> >>> setup for auto-
> >>> POJO classes. I proposed this before and in
> most java
> >>> circles (outside
> >>> of coin-dev!), this idea was considered very
> useful:
> >>>
> >>> public data class Foo {
> >>>     private final int x;
> >>>     private final int y;
> >>>     private final String foo;
> >>> }
> >>>
> >>>
> >>> The above class would auto-generate the
> getters, a
> >>> constructor,
> >>> hashCode, equals, and toString. You can add
> methods to it
> >>> if you want,
> >>> and if you define a method that would usually
> be
> >>> auto-generated, it
> >>> isn't auto-generated. So, if you need to
> do some extra
> >>> processing
> >>> before returning 'foo' via the getter,
> go right
> >>> ahead. You can even
> >>> add this later without breaking your API's
> >>> compatibility.
> >>>
> >>>  --Reinier Zwitserloot
> >>>
> >>>
> >>>
> >>> On Mar 25, 2009, at 02:07, Mark Mahieu wrote:
> >>>
> >>>> HTML version + prototype available at
> >>> http://slm888.com/javac
> >>>>
> >>>>
> >>>>
> >>>> Auto-assignment Parameters v0.1
> >>>>
> >>>>
> >>>> AUTHOR(S):
> >>>>
> >>>> Mark Mahieu
> >>>>
> >>>>
> >>>> OVERVIEW
> >>>>
> >>>> FEATURE SUMMARY: Should be suitable as a
> summary in a
> >>> language
> >>>> tutorial.
> >>>>
> >>>> An additional form of constructor
> parameter which
> >>> provides automatic
> >>>> assignment of the parameter's value to
> an instance
> >>> field.  These
> >>>> parameters
> >>>> are implicitly declared as final to
> prevent
> >>> unintentional
> >>>> assignments to the
> >>>> wrong variable in the constructor body.
> >>>>
> >>>>
> >>>> MAJOR ADVANTAGE: What makes the proposal a
> favorable
> >>> change?
> >>>>
> >>>> Reduces the likelihood of some common
> coding errors
> >>> relating to
> >>>> assignment
> >>>> of fields in a constructor, including
> those where:
> >>>>
> >>>>   * a field is assigned to itself
> >>>>   * the parameter is assigned instead of
> the field
> >>>>   * the assignment to the field is
> missing entirely
> >>>>
> >>>> These and other errors are often caused by
> typos or
> >>> code refactoring.
> >>>>
> >>>>
> >>>> MAJOR BENEFIT: Why is the platform better
> if the
> >>> proposal is adopted?
> >>>>
> >>>> A programmer's intent is more clearly
> expressed
> >>> for the extremely
> >>>> common
> >>>> case of assigning a constructor parameter
> directly to
> >>> an instance
> >>>> field with
> >>>> the same name.
> >>>>
> >>>>
> >>>> MAJOR DISADVANTAGE: There is always a
> cost.
> >>>>
> >>>> As with any sugar which enables a more
> concise way of
> >>> expressing an
> >>>> existing
> >>>> idiom, programmers may be tempted to use
> it even when
> >>> the original
> >>>> form
> >>>> would be more appropriate.
> >>>>
> >>>>
> >>>> ALTERNATIVES: Can the benefits and
> advantages be had
> >>> some way
> >>>> without a
> >>>> language change?
> >>>>
> >>>> IDEs and tools such as FindBugs are good
> at warning
> >>> about the kind
> >>>> of errors
> >>>> mentioned above, however since the code in
> question is
> >>> usually still
> >>>> valid
> >>>> to the compiler, they are limited in what
> action they
> >>> can take by
> >>>> default.
> >>>>
> >>>> A language change can combine the ability
> to avoid
> >>> these errors
> >>>> entirely
> >>>> with a more expressive idiom, resulting in
> an
> >>> increased signal to
> >>>> noise
> >>>> ratio for readers of that code.
> >>>>
> >>>>
> >>>>
> >>>> EXAMPLES
> >>>>
> >>>> SIMPLE EXAMPLE: Show the simplest possible
> program
> >>> utilizing the new
> >>>> feature.
> >>>>
> >>>>   class C {
> >>>>       int i;
> >>>>       C(int this.i) {}
> >>>>   }
> >>>>
> >>>>
> >>>> ADVANCED EXAMPLE: Show advanced usage(s)
> of the
> >>> feature.
> >>>>
> >>>>
> >>>>   class Proposal {
> >>>>
> >>>>       private final String name;
> >>>>       private final String author;
> >>>>       private boolean suitableForCoin;
> >>>>       private Integer score;
> >>>>
> >>>>       public Proposal(String this.name,
> >>>>                       String
> this.author,
> >>>>                       boolean
> this.suitableForCoin,
> >>>>                       int
> this.score) {
> >>>>
> >>>>           if
> (name.equals(“Auto-assignment
> >>> Parameters”)) {
> >>>>              suitableForCoin =
> true; // final so
> >>> compile-time error
> >>>>           }
> >>>>       }
> >>>>
> >>>>       // rest of class ...
> >>>>   }
> >>>>
> >>>>
> >>>>
> >>>> DETAILS
> >>>>
> >>>>
> >>>> SPECIFICATION: Describe how the proposal
> affects the
> >>> grammar, type
> >>>> system,
> >>>> and meaning of expressions and statements
> in the Java
> >>> Programming
> >>>> Language
> >>>> as well as any other known impacts.
> >>>>
> >>>> The syntactic grammar is modified to
> include
> >>> auto-assignment
> >>>> parameters for
> >>>> constructors:
> >>>>
> >>>>       ConstructorDeclaratorRest:
> >>>>              
>  ConstructorParameters [throws
> >>> QualifiedIdentifierList]
> >>>> MethodBody
> >>>>
> >>>>       ConstructorParameters:
> >>>>                (
> [ConstructorParameterDecls] )
> >>>>
> >>>>       ConstructorParameterDecls:
> >>>>                [final]
> [Annotations] Type
> >>>> ConstructorParameterDeclsRest
> >>>>
> >>>>       ConstructorParameterDeclsRest:
> >>>>              
>  ConstructorParameterId [ ,
> >>> ConstructorParameterDecls]
> >>>>                ...
> ConstructorParameterId
> >>>>
> >>>>       ConstructorParameterId:
> >>>>              
>  VariableDeclaratorId
> >>>>                this .
> VariableDeclaratorId
> >>>>                super .
> VariableDeclaratorId
> >>>>
> >>>> An auto-assignment parameter is a formal
> parameter
> >>> (JLSv3 §8.4.1)
> >>>> which
> >>>> specifies an instance field instead of an
> identifier.
> >>> Its value is
> >>>> automatically assigned to the specified
> field.  It may
> >>> only be used
> >>>> in a
> >>>> constructor.
> >>>>
> >>>> The automatic assignment takes place after
> any
> >>> explicit or implicit
> >>>> invocation of another constructor, and
> before any
> >>> statements in the
> >>>> body of
> >>>> the constructor.  A constructor which
> declares n
> >>> auto-assignment
> >>>> parameters
> >>>> will perform n such automatic assignments,
> in the
> >>> order that the
> >>>> parameters
> >>>> are declared.
> >>>>
> >>>> The parameter has the same name (JLSv3
> §6.2) as the
> >>> field to which
> >>>> it is
> >>>> assigned; replacing each auto-assignment
> parameter
> >>> with a normal
> >>>> formal
> >>>> parameter with the same name would yield a
> constructor
> >>> with an
> >>>> identical
> >>>> signature.  As with a normal parameter,
> the
> >>> parameter's name is
> >>>> entered into
> >>>> the scope of the constructor body (JLSv3
> §6.3), and
> >>> therefore
> >>>> shadows the
> >>>> field (JLSv3 §6.3.1) within that scope.
> >>>>
> >>>> It is a compile-time error if the field is
> not
> >>> accessible from the
> >>>> constructor in which the parameter
> appears.
> >>>>
> >>>> It is a compile-time error if the declared
> type of the
> >>> parameter is
> >>>> not
> >>>> assignment compatible (JLSv3 §5.2) with
> the field to
> >>> which it is
> >>>> automatically assigned.
> >>>>
> >>>> If an unboxing conversion is required by
> an automatic
> >>> assignment, any
> >>>> NullPointerException thrown as a result
> (JLSv3
> >>> §5.1.8) will contain
> >>>> the name
> >>>> of the field on which the conversion
> failed, which may
> >>> be retrieved by
> >>>> calling getMessage() on the exception.
> >>>>
> >>>> Auto-assignment parameters are implicitly
> final, and
> >>> follow the
> >>>> standard
> >>>> rules for final variables (JLSv3
> §4.12.4).
> >>> Explicitly declaring an
> >>>> auto-assignment parameter as final has no
> effect, and
> >>> does not cause a
> >>>> compilation error.
> >>>>
> >>>> Auto-assignment parameters follow the
> standard
> >>> definite assignment
> >>>> rules for
> >>>> formal parameters (JLSv3 §16.3).
> >>>>
> >>>> An auto-assignment parameter may be
> annotated.
> >>>>
> >>>> If an auto-assignment parameter is the
> last parameter
> >>> in the list, and
> >>>> refers to a field of array type, it may be
> a variable
> >>> arity parameter.
> >>>>
> >>>>
> >>>>
> >>>> COMPILATION: How would the feature be
> compiled to
> >>> class files? Show
> >>>> how the
> >>>> simple and advanced examples would be
> compiled.
> >>> Compilation can be
> >>>> expressed
> >>>> as at least one of a desugaring to
> existing source
> >>> constructs and a
> >>>> translation down to bytecode. If a new
> bytecode is
> >>> used or the
> >>>> semantics of
> >>>> an existing bytecode are changed, describe
> those
> >>> changes, including
> >>>> how they
> >>>> impact verification. Also discuss any new
> class file
> >>> attributes that
> >>>> are
> >>>> introduced. Note that there are many
> downstream tools
> >>> that consume
> >>>> class
> >>>> files and that they may to be updated to
> support the
> >>> proposal!
> >>>>
> >>>> Desugaring of the following class:
> >>>>
> >>>>   class Foo {
> >>>>       int value;
> >>>>       Foo(Integer this.value) {
> >>>>           System.out.println(value);
> >>>>       }
> >>>>   }
> >>>>
> >>>> would result in (unboxing desugaring
> omitted):
> >>>>
> >>>>   class Foo {
> >>>>       int value;
> >>>>       Foo(final Integer value) {
> >>>>           super();
> >>>>           if (value == null)
> >>>>               throw new
> >>> NullPointerException("value");
> >>>>           this.value = value;
> >>>>           System.out.println(value);
> >>>>       }
> >>>>   }
> >>>>
> >>>> No changes to the classfile format are
> required.
> >>> Tools which
> >>>> consume class
> >>>> files see the constructor signature as
> though it had
> >>> been written
> >>>> using
> >>>> normal formal parameters.
> >>>>
> >>>>
> >>>> TESTING: How can the feature be tested?
> >>>>
> >>>> An initial set of jtreg tests is included
> in the
> >>> prototype.
> >>>>
> >>>>
> >>>> LIBRARY SUPPORT: Are any supporting
> libraries needed
> >>> for the feature?
> >>>>
> >>>> No
> >>>>
> >>>>
> >>>> REFLECTIVE APIS: Do any of the various and
> sundry
> >>> reflection APIs
> >>>> need to be
> >>>> updated? This list of reflective APIs
> includes but is
> >>> not limited to
> >>>> core
> >>>> reflection (java.lang.Class and
> java.lang.reflect.*),
> >>>
> >>>> javax.lang.model.*,
> >>>> the doclet API, and JPDA.
> >>>>
> >>>> com.sun.source.tree.VariableTree would
> require an
> >>> additional method
> >>>> which
> >>>> returns the auto-assigned field.
> >>>>
> >>>>
> >>>> OTHER CHANGES: Do any other parts of the
> platform need
> >>> be updated too?
> >>>> Possibilities include but are not limited
> to JNI,
> >>> serialization, and
> >>>> output
> >>>> of the javadoc tool.
> >>>>
> >>>> No
> >>>>
> >>>>
> >>>> MIGRATION: Sketch how a code base could be
> converted,
> >>> manually or
> >>>> automatically, to use the new feature.
> >>>>
> >>>> Assignment statements in constructors for
> which all of
> >>> the following
> >>>> are
> >>>> true can be considered suitable for
> conversion:
> >>>>    * the lhs of the assignment is a
> non-static field
> >>>>    * the rhs is a parameter with the
> same name as the
> >>> field
> >>>>    * there are no other assignments to
> the parameter
> >>> anywhere in the
> >>>> constructor
> >>>>    * there are no assignments to, or
> other uses of
> >>> the field before
> >>>> the
> >>>> assignment statement in question
> (including invoked
> >>> constructors)
> >>>>
> >>>> Such statements can be converted by:
> >>>>   1) replacing the parameter with an
> auto-assignment
> >>> parameter
> >>>> (prefixing
> >>>> the existing parameter's identifier
> with
> >>> 'this.'), and
> >>>>   2) removing the assignment statement
> >>>>
> >>>>
> >>>>
> >>>> COMPATIBILITY
> >>>>
> >>>> BREAKING CHANGES: Are any previously valid
> programs
> >>> now invalid? If
> >>>> so, list
> >>>> one.
> >>>>
> >>>> No
> >>>>
> >>>>
> >>>> EXISTING PROGRAMS: How do source and class
> files of
> >>> earlier platform
> >>>> versions interact with the feature? Can
> any new
> >>> overloadings occur?
> >>>> Can any
> >>>> new overriding occur?
> >>>>
> >>>> The semantics of existing class files and
> legal source
> >>> files are
> >>>> unchanged
> >>>> by this feature.
> >>>>
> >>>>
> >>>>
> >>>> REFERENCES
> >>>>
> >>>> EXISTING BUGS: Please include a list of
> any existing
> >>> Sun bug ids
> >>>> related to
> >>>> this proposal.
> >>>>
> >>>>
> >>>
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6582394
> >>>> (uses a 'setter' method rather
> than a
> >>> constructor in its example)
> >>>>
> >>>> FindBugs bug patterns -
> >>>
> http://findbugs.sourceforge.net/bugDescriptions.html
> >>>> * Self assignment of field
> (SA_FIELD_SELF_ASSIGNMENT)
> >>>> * Self comparison of field with itself
> >>> (SA_FIELD_SELF_COMPARISON)
> >>>> * Nonsensical self computation involving a
> field
> >>> (e.g., x & x)
> >>>> (SA_FIELD_SELF_COMPUTATION)
> >>>> * Self assignment of local variable
> >>> (SA_LOCAL_SELF_ASSIGNMENT)
> >>>> * Nonsensical self computation involving a
> variable
> >>> (e.g., x & x)
> >>>> (SA_LOCAL_SELF_COMPUTATION)
> >>>> * Uninitialized read of field in
> constructor
> >>> (UR_UNINIT_READ)
> >>>> * Unwritten field (UWF_UNWRITTEN_FIELD)
> >>>> * Dead store to local variable
> (DLS_DEAD_LOCAL_STORE)
> >>>> * Dead store of null to local variable
> >>> (DLS_DEAD_LOCAL_STORE_OF_NULL)
> >>>>
> >>>>
> >>>>
> >>>> URL FOR PROTOTYPE (optional):
> >>>>
> >>>> http://slm888.com/javac
> >>>>
> >>>>
> >>>>
> >>>> DESIGN ALTERNATIVES:
> >>>>
> >>>> The following variations have been
> explored and are
> >>> worth mentioning:
> >>>>
> >>>> * Allow auto-assignment parameters on all
> non-abstract
> >>> methods.
> >>>>   This may be especially useful on the
> extremely
> >>> common 'setter'
> >>>> methods
> >>>> in 'value object' classes.
> >>>>
> >>>> * Remove the requirement for (or even
> disallow) the
> >>> type to be
> >>>> specified on
> >>>> auto-assignment parameters.
> >>>>   Experimentation with this idea suggests
> that it may
> >>> work quite
> >>>> well for
> >>>> constructors, further emphasising the
> difference in
> >>> intent and
> >>>> semantics
> >>>> from those of normal parameters. However,
> it may not
> >>> work so well in
> >>>> combination with auto-assignment
> parameters on all
> >>> non-abstract
> >>>> methods, and
> >>>> requires a change to the order in which
> javac compiles
> >>> classes (can
> >>>> still
> >>>> pass jtreg tests).
> >>>>
> >>>> * Allow an alternative name to be
> specified.
> >>>>   This adds additional complexity to
> support a
> >>> fractional
> >>>> percentage of
> >>>> cases, which could continue to use the
> existing coding
> >>> pattern.
> >>>>
> >>
> >>
> >>
> >>
> >
> >
> >


      



More information about the coin-dev mailing list