It's the data, stupid !

forax at univ-mlv.fr forax at univ-mlv.fr
Mon May 30 19:45:26 UTC 2022


> From: "Brian Goetz" <brian.goetz at oracle.com>
> To: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
> Sent: Monday, May 30, 2022 8:40:33 PM
> Subject: Re: It's the data, stupid !

>> The problem is that what you propose is a leaky abstraction, because pattern
>> matching works on classes and not on types, so it's not a reverse link.

> ("Leaky abstraction" is sort of an inflammatory term.)

> What I think you're getting at is that some objects will have state that you can
> "put in", but can't "take out". The mathematical relationship here is
> "embedding projection pair" (this is similar to an adjoint functor pair in some
> ways.)

> A good example of this relationship is int and Integer. Every int corresponds to
> an Integer, and *almost* every Integer (except null) corresponds to an int.
> Imagine there are two functions e : int -> Integer and p : Integer -> int,
> where p(null) = bottom. Composing e-then-p is an identity; composing p-then-e
> can lose some information, but we can characterize the information loss.
> Records form this same relationship with their cartesian product space
> (assuming you follow the refined contract outlined in Record::equals). When you
> have this relationship, you get some very nice properties, such as "withers"
> and serialization basically for free. The relationship between a ctor and the
> corresponding dtor also has this structure. So yes, going backwards is "lossy",
> but in a controlled way. This turns out to be good enough for a lot of things.
I don't disagree about everything you are saying, because the problem is elsewhere. 

>> Let say we have a class with two shapes/deconstruction

>> class A {
>> deconstructor (B) { ... }
>> deconstructor (C) { ... }
>> }

>> With the pattern A(D d), D is a runtime class not a type, you have no idea if it
>> means
>> instanceof A a && B b = a.deconstructor() && b instanceof D
>> or
>> instanceof A a && C c = a.deconstructor() && c instanceof D

> You can have types in the dtor bindings, just as you can have types in the
> constructor arguments. Both may use the class type variables, as they are
> instance "members".
The problem is not at callee site, as you said you have deconstructor binding like you have constructor parameter, the problem is at callsite, when you have a Type Pattern, a type pattern does not declare a type that can be used at compile time but a class that is used at runtime (to do the instanceof). 
So the problem is not how to declare several deconstructors, it's how to select the right one without type information. 

This is a problem specific to the switch or instanceof, if you have an assignment context, here because the matching is total, you can extract the types from the expression you are matching. 
By example with 
A(D d) = a; 

here D is a type, not a class, so finding the right descriptor is easy, you can apply the same algorithm as the overloading selection. 

But with instanceof, 
a instanceof A(D d) 

here D is a class, you can not find the corresponding type, so you can not run the overloading selection. 

>> As i said, it's a question where OOP and DOD (data oriented design ?) disagree
>> one with the other.

> I don't think they disagree at all. They are both useful tools for modeling
> things; one is good for modeling entities and processes, the other for modeling
> data, using a common vocabulary. Our systems may have both!
yes, the question is when both disagree, who is winning ? for all cases where they both disagree. 

>> And this is a problem specific to the deconstructor, for named pattern method,
>> there is no such problem, obviously a user can add as many pattern methods
>> he/she want.

> Because there's no name, we are limited to overloads that are distinct up to
> erasure; constructors have the same restriction.
nope, because if we have a type pattern / record pattern we have no type information. 
If named pattern method allows overloading, we will have the same issue, there is not enough type information at callsite. 

>>> But for each way of putting together the data, there should be a corresponding
>>> way to take it apart.
>> if the pattern matching was a real inverse link, yes, maybe.

> I think the word "real" is doing too much lifting in that sentence.

>> The problem is that varargs pattern can also recognizes a record with no record
>> or class with a deconstructor with no varargs.

> As can a constructor.
no, there is no spread operator in Java unlike by example in JavaScript, so you can not write 
class A { 
A(int i, int j) { ... } 
} 

int[] array = ... 
new A(...array) 

> I think the reality is that you want this to be a smaller, less ambitious
> feature than is being planned here. That's a totally valid opinion! But I think
> its just a difference of opinion on how much to invest vs how much we get out.

> But by all means, try to outline (in a single mail, please) your vision for a
> simpler model.
By simpler model, i mean we do not have to mirror all the method call quirks as patterns, only the ones that make sense from a "data oriented design" POV. 

Rémi 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20220530/56cd06df/attachment-0001.htm>


More information about the amber-spec-experts mailing list