It's the data, stupid !
Brian Goetz
brian.goetz at oracle.com
Mon May 30 18:40:33 UTC 2022
>
> 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.
> 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".
> Unlike with a method call (constructor call) where the type of the
> arguments are available, with the pattern matching, you do not have
> the types of the arguments, only runtime classes to match.
This is where the rule of "downcast compatible" comes in. We see this
show up in GADT-like examples (the rules of which are next on our
parade.) For example, if we have:
sealed class Node<T> { }
record IntNode(int x) implements Node<int> { }
then when we switch on a Node<T>:
switch (aNode) {
case IntNode n: ...
}
we may conclude, in the consequent of the appropriate case, that T=int.
(Read the Kennedy and Russo paper for details.)
Similarly, if we have:
List<String> list = ...
then when matching, we may conclude that if its an ArrayList, its an
ArrayLIst<String>:
switch (list) {
case ArrayList<String> a: ...
}
but could not say `case ArrayList<Integer>`, because that is
inconsistent with the target type.
So, while we can't necessarily distinguish between Foo<String> and
Foo<Integer> because of erasure, that doesn't mean we can't use types;
its just that we can't conclude things that the generic type system
won't let us.
> 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!
> 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.
> 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.
>
> You think term of inverse function, we have varargs constructors so we
> should have varargs pattern, but a pattern is not an inverse function.
You are interpreting "inverse" too strictly -- and then attempting to
use that to prematurely bury the concept.
> We have the freedom to provide a simpler model.
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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20220530/766437b4/attachment.htm>
More information about the amber-spec-experts
mailing list