It's the data, stupid !
Brian Goetz
brian.goetz at oracle.com
Mon May 30 16:40:22 UTC 2022
> First, i've overlook the importance of the record pattern as a check
> of the shape of the data.
>
> Then if we say that data are more important than code and that the aim
> of the pattern matching is to detect changes of the shapes of the data,
> it changes the usefulness of some features/patterns.
OK, now that I see what argument you are really winding up for, I think
I'm going to disagree. Yes, data-as-data is a huge benefit; it is
something we were not so good at before, and something that has become
more important over time. That has motivated us to *prioritize* the
data-centric features of pattern matching over more general ones,
because they deliver direct value the soonest. But if you're trying to
leverage that into a "this is the only benefit" (or even the main
benefit), I think that's taking it too far.
The truly big picture here is that pattern matching is the dual of
aggregation. Java gives us lots of ways to put things together
(constructors, factories, builders, maybe some day collection literals),
but the reverse of each of these is ad-hoc, different, and usually
harder-to-use / more error-prone. The big picture here is that pattern
matching *completes the object model*, by providing the missing reverse
link. (In mathematical terms, a constructor and deconstructor (or
factory and static pattern, or builder and "unbuilder", or collection
literal and collection pattern) form an *embedding-projection pair*.)
Much of this was laid out in Pattern Matching in the Java Object Model:
https://github.com/openjdk/amber-docs/blob/master/site/design-notes/patterns/pattern-match-object-model.md
> it makes the varargs pattern a kind of harmful, because it matches
> data of several shapes, so the code may still compile if the shape of
> the record/data-type change.
I think you've stretched your argument to the breaking point. No one
said that each pattern can only match *one* structure of data. But for
each way of putting together the data, there should be a corresponding
way to take it apart.
> - the varargs pattern can be emulated by an array pattern and it's
> even better because an array pattern checks that the shape is an array and
Well, we don't have array patterns yet either, but just as varargs
invocation is shorthand for a manually created array, varargs patterns
are shorthand for an explicit array pattern.
> The result is that i'm not sure the vararg pattern is a target worth
> pursuing.
I think its fine to be "not sure", and its doubly fine to say "I'm not
sure the cost-benefit is so compelling, maybe there are other features
that we should do first" (like array patterns.) But if you're trying to
make the argument that varargs patterns are actually harmful, you've got
a much bigger uphill battle.
And don't forget, records are just the first vehicle here; this is
coming for arbitrary classes too. And being able to construct things
via varargs construction, but not take them apart by varargs patterns,
seems a gratuitous inconsistency. (Again, maybe we decide that better
type inference is worth doing first, but the lack of varargs will still
be a wart.)
> Deconstructors of a class also becomes a kind of a war ground between
> the OOP and the pattern matching, OOP says that API is important and
> pattern matching says it's ok to change the data changing the API
> because the compiler will points where the code should be updated.
> We still want encapsulation because it's a class but we want to detect
> if its shape change so having a class with several shapes becomes not
> as useful as i first envision.
No, these are not in conflict at all. The biggest tool OOP offers us is
encapsulation; it gives us a way to decide how much state we want to
expose, in what form, etc, fully decoupled from the representation.
(Records don't have this option for decoupling representation from API,
which is what makes it so easy to deliver these features first for
records.) Most classes still choose to give clients _some_ way to
access most of the state we pass into the constructor and other API
points; its just that this part of the API is usually gratuitously
different (e.g., accessors, wrapping with Optional) from the part where
state goes in. Which means that we *do* expose the state to readers,
just in a gratuitously different way that we do to writers. What
pattern matching does is gives us exactly the same control we have today
over what to expose, and in what form, but lets us do it in a way that
is structurally related to how we put state into objects. It does so
with combining multiple return, conditionality, and flow analysis in an
integrated way, so we don't have to reinvent these in an ad-hoc way in
every class.
So while we agree that records + sealed classes + pattern matching
enable a nice form of data-oriented programming, and that was indeed a
big goal, I think the model you're trying to extrapolate about what the
"point" of pattern matching is may be missing its mark. There's a bigger
picture here.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20220530/5d90aa02/attachment-0001.htm>
More information about the amber-spec-experts
mailing list