Reference SUB/SEP Value question
Tobi Ajila
atobia at ca.ibm.com
Wed Dec 10 16:56:35 UTC 2014
>I think there are two choices, refSUBvalue and refSEPvalue.
>
>For SUB, you might have a hierarchy that looks like this:
>
> interface ComplexValue
> class Complex implements ComplexValue
> interface ComplexRef extends ComplexValue, Ref
> class ComplexGeneratedProxy implements ComplexRef
>
>You can do this because a Reference can support all the
>methods of Value by fetching the relevant fields etc, plus
>it has some more methods for setting those fields.
It seems like the reason to separate ComplexRef and ComplexValue is to be
able to treat the Value as an immutable value holder. Correct? If Ref
subclasses Value, it will be easy for "immutable" things to change, either
by casting to the Ref or by having someone else modify the Ref while you
read the Value, and we start to tread on C++ const casts. e.g.
ComplexRef refType = Ref.instantiate(ComplexRef.class);
ComplexValue valueType = (ComplexValue) refType;
//now we have a mutable and immutable version of the same data
>For SEP, you might have a hierarchy that looks like this:
>
> interface ComplexValue
> class Complex implements ComplexValue
>
> interface ComplexRef extends Ref {
> ComplexValue get(); // canonical connection between Ref and Value
> }
> class ComplexGeneratedProxy implements ComplexRef
With Ref and Value being unrelated, we run into issues because we can't
cast between them. This feels a lot like C++'s reference vs pointer and
will lead to similar user frustrations when they can't convert between the
Value and Ref. This seems contrary to our objections about the Value and
Ref being related, but I think both situations are going to cause similar
issues.
An alternative proposal is something like the following:
interface ComplexRef extends Ref
class Complex implements ComplexRef {
ComplexRef freeze() { ... } // this returns an immutable Ref
type
}
Ref.instantiate(Ref refType, LD description);
In this hierarchy there are only Ref types. Immutability is a state and not
a type, this state can be achieved by calling the 'freeze' method.
> ComplexRef (in particular) is very likely to be a single-implementation
> interface (the proxy class) and thus will be easy to optimize.
Our users also want to be able to add their own behaviour to the generated
classes. For example, they want to modify the generated 'ComplexRef'
interface and add new default methods like 'getAbsValue()'. Users
modifying generated artifacts will run into maintenance headaches every
time they need to re-run the groveller, which could be quite frequent
during development.
We would like them to be able to create their own interfaces that extend
the ones generated by the groveller. Something like, 'MyComplexRef extends
ComplexRef', where 'MyComplexRef' would implement the user functionality.
This will affect the API used to instantiate a ComplexRef as it would be
necessary to pass in the required interface. e.g.
<T extends Ref> T instantiate(Class<T extends Ref> clazz, LD
description)
and the user would call this like:
MyComplexRef ref = Ref.instantiate(MyComplexRef.class, LD);
This design undermines the assumption that ComplexRef will typically have
one implementor. Do you agree with how we bind user-defined behaviour to
layouts? What is the best way to do this?
More information about the panama-spec-experts
mailing list