Revisiting .ref and .value

Gernot Neppert mcnepp02 at googlemail.com
Tue Jul 21 08:07:44 UTC 2020


If I've got this right, the way for specifying which variant of an inline
class to use, one would have to use one of the suffixes .ref or .value.
Existing classes refactored as inline classes could somehow specify that
.ref was the default, whereas new inline classes would have .value the
default.

What strikes me as odd is the fact that we are now having 4 new terms that
would have to be understood by the developer:
- the keyword 'inline' that declares a class that represents a value-type.
- the keyword-suffix '.val' that says "At this point, use the inline
representation of a class".
- the keyword-suffix '.ref' that says "At this point, use the regular
non-inline representation of a class".
- the Standard interface "IdentityObject" that probably most often will be
encountered as a type-bound for a generic function or class.

This makes me think: do we really need to learn so many different terms
when they are so closely related?

Couldn't we do without the '.val' and '.ref' suffixes if we shifted towards
decorating the *type-use* instead of the *type* itself?
Which leads me to this idea:

1. A declaration "inline class Bar" would always declare a 'ref-default"
class. The purpose of 'inline' here would be simply to enforce certain
restrictions, such as final fields etc.
2. inline classes would not implement the interface "IdentityObject".
3. In order to make use of the "inline characteristics", one would have to
specify "inline" again:

class Outer {
Bar byRef; // ref-member, may be null.
inline Bar embedded; // inline member, mandates the same
definite-assignment rule as that for final fields.
}


// inline return-value and inline parameters will copy by-value.
inline Bar calculate(inline Bar bar) {
    inline Bar temp = bar; // inline local var, will copy by-value.
   // inline array. Must use an initializer-instance that will be used for
all array-members.
    inline Bar[] arr = new Bar[10] { new Bar("") };
}

// ref-return-value and ref-parameters
Bar calculate(Bar bar) {
         Bar temp = bar; // local var, assigns the reference only.
}

// generic function requires inline-class, so copy-by-value may be used
<C> void foo(inline C) {
}

// normal generic function for any ref-type. Will use implicit
reference-projection if an inline-value is passed
<C> void foo(C obj) {
}

// generic function that explicitly requires non-inline class.
// By requiring IdentityObject, we know that 'obj' cannot be the result of
a reference-projection, so we can safely synchronize on it!
<C extends IdentityObject> void foo(C obj) {
  synchronized(obj) {
  }
}

// Conflicting declaration, will be rejected by compiler
<C extends IdentityObject> void foo(inline C obj) {
  synchronized(obj) {
  }
}


More information about the valhalla-spec-observers mailing list