Is case var(var x, var y) a valid syntax ?
forax at univ-mlv.fr
forax at univ-mlv.fr
Sun Sep 13 18:20:15 UTC 2020
> De: "Brian Goetz" <brian.goetz at oracle.com>
> À: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
> Envoyé: Dimanche 13 Septembre 2020 15:42:39
> Objet: Re: Is case var(var x, var y) a valid syntax ?
>>> - While instance members, they are not inherited (just like constructors)
>> At least you want a deconstructor to be overrideable (which is not fully
>> equivalent to being inherited).
>> A deconstructor is for allowing encapsulation so the world projected by a
>> deconstructor may have a little to share with how the the class are implemented
>> class Employee {
>> int baseSalary;
>> deconstructor Employee(int salary) { return (baseSalary); }
>> }
>> class VP extends Employee {
>> int bonus;
>> deconstructor VP(int salary) { return (baseSalary + bonus); }
>> }
>> ...
>> Vp vp = new VP();
>> vp.setBaseSalary(2000);
>> vp.setBonus(500);
>> Employee employee = vp;
>> if (employee instanceof Employee(salary) {
>> System.out.println(salary); // 2500
>> }
>> and here you can see that Employee(salary) is not a call to the deconstructor
>> but an instanceof Employee + a call to the deconstructor (int salary) !
> I think what you are alluding to here is the idea that a deconstructor is like a
> “multi-accessor”, and accessors are virtual but deconstructors are not.
> But the example is distorted for two reasons; this is already a questionable
> deconstructor API, and even if so, Employee is conflicted about the distinction
> between salary and baseSalary.
if deconstructors are not virtual, Is the salary printed is 2000 or the compiler raises an error somewhere ?
> So I’m not sure how much we can learn from this particular example. Maybe you
> have a better one?
No a better one, just another one, you want to be able to declare a deconstructor abstract by example on an interface
interface Map {
interface Entry<K,V> {
public abstract deconstructor Entry(K key, V value);
}
}
...
for(Map.Entry<String, String>(var key, var value) : entries) {
...
}
BTW, it's also an example where 'var' can be useful instead of having to specify the full type
for(var(var key, var value) : entries) {
...
}
>>> - They can only be called via a pattern match (just as a constructor can only be
>>> called via a `new` operation.)
>> so unlike a constructor that can be called either by a new or by this(...) and
>> super(...) a deconstructor can only be called via pattern matching.
> You should re-read the document about deconstructors, as this symmetry is well
> covered. The case of one deconstructor delegating to another, just like one
> constructor delegating to another, is important, because we want each class to
> be responsible for its own state. So yes, this is covered. (Technically,
> though, this sort of delegated invocation _is_ a pattern match, so the
> statement “only through pattern matching” still stands.)
I get that you can write the code like this if baseSalary is declared private in Employee
class VP extends Employee {
int bonus;
deconstructor VP(int salary) {
super(var baseSalary) = this;
return (baseSalary + bonus);
}
}
still, a deconstructor is unlike a constructor because you can call a constructor directly something you can not do with a deconstructor.
>>> In this way, both ctor and dtor mediate access between an external API and the
>>> internal representation.
>> It's only true for a constructor if the constructor (constructors) are the only
>> way to change the value of an instance.
>> It's only true for a deconstructor if the deconstructor has a matching
>> constructor
> Both of these “only true” claims are not true :)
> You can have multiple constructors with different views of the state
> (overloading), and these views could be overlapping or non-overlapping. And you
> can have multiple deconstructors with different views of the state too. And
> have the choice to align the constructor / deconstructor views, or not. You can
> have matching ctor/dtor, or asymmetric ones — this is a matter of API design.
so why my first example is questionable usage of the deconstructor API.
> We anticipate it will be common to provide matched ctor/dtor pairs, because
> together these form an adjunction between the state space of the object and the
> external API shared between ctor/dtor, which is a useful and practical building
> block.
> Even for mutable objects, deconstructors are still sensible.
> class C {
> int x;
> C(int x) { this.x = x; }
> deconstructor C(int x) { x = this.x; }
> void setX(int x) { this.x = x; }
> }
> I can do:
> C c = new C(3);
> c.setX(4);
> if (c instanceof C(var x)) { … x is 4 here … }
> The deconstructor is free to track the state, mutable or not. Again, this is a
> tool for API design, and it can be used in multiple ways. The record case is
> notable because records have a highly constrained API and they are not
> extensible, so they are the best behaved of the bunch. But classes can play
> this game too.
and now introduce inheritance to the mix and you will see that a deconstructor has to be virtual.
Basically, we are at the point where it's not useful anymore to call it a deconstructor because while it's like the reverse of a constructor, at the same time it's also close to an API like clone().
Rémi
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20200913/b34597da/attachment-0001.htm>
More information about the amber-spec-experts
mailing list