Fwd: Record invariants vs constructor/destructor identity

Brian Goetz brian.goetz at oracle.com
Tue Mar 12 12:34:15 UTC 2019

Received on amber-spec-comments.  

My comments: This is a nice direction, but in order to make it work, the language would need an actual concept of factory methods, so that the pattern of “private ctor, public factory” could be counted upon.  So the fact that they are known to users is necessary but not sufficient; they would also need to be known _to the language_.  

> Begin forwarded message:
> From: Victor Nazarov <asviraspossible at gmail.com>
> Subject: Record invariants vs constructor/destructor identity
> Date: March 11, 2019 at 12:08:38 PM EDT
> To: amber-spec-comments at openjdk.java.net
> Recent discussion on amber experts list considers particularities of
> constructor overriding for records.
> There seems to be a tension between two requirements:
> 1. Records should be it's state only state and nothing but state
> 2. Records should enforce some requirements considering state
> (There was a third requirement that records should allow derived state that
> facilitate more optimizations, but I won't touch this point in this
> message).
> What I'd like to point out is that ML-family languages already implement
> first maxima that "Records should be it's state only state and nothing but
> state" and simultaneously deals with enforcement of invariants.
> And I think the was it is implemented in languages like Haskell,
> StandardML, etc is quite successful.
> In ML-laguages constructor and destructor ALWAYS form an identity and users
> are quite accustomed to and rely on this. But types like `Rational` needs
> to preprocess it's data to be useful and you can do it in ML-languages. To
> do it, you just need to (TM) use a mechanism that you already have: private
> constructor. So `Rational` becomes:
>    private-constructor record Rational(int num, int denom) {
>          public static Rational makeRational(int num, int denom) {
>              int gcd = gcd(num, denim);
>              num /= gcd;
>              denom /= gcd;
>              return new Rational(num, denom);
>          }
>    }
> User knows that constructor/destructor identity always holds in any order,
> user gets access to all internal representation, but user can't break class
> invariant because they don't have access to direct constructor call.
> User model remains clear and simple.
> The following properties always hold
>      record Foo(int x, int y)
>      assert new Foo(1, 2).x() == 1
>      assert new Foo(1, 2).y() == 2
> but sometimes user can't create every representable record instance.
> Factory-method is here to moderate instance creation. And factory methods
> are already known mechanism for Java-programmers.
> --
> Victor Nazarov

More information about the amber-spec-observers mailing list