<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<br>
So, I want to make sure this conversation stays on track. You asked
"why does it work this way", and you got an answer. And its OK to
ask follow-up questions for clarification. But we need to steer
away from the (irresistibly tempting, I know) track of "let's
redesign the feature", and we're in danger of veering into that.
These issues were well considered during the design already, and
these questions are not new. As mentioned, we did explicitly
consider public fields, and concluded that would be a bad idea. (I
know this may sound unfriendly, but just consider how this scales.
There are 10M Java developers, who may each independently have their
own ideas about how a feature should be designed, and want to
"debate" it, sequentially and independently and possibly
inconsistently, with the language designers.) <br>
<br>
Now, to your question.<br>
<br>
<blockquote type="cite" cite="mid:CAJuA9EiPbyf2NBqfFiuAndma0__A7vk60hz6N4-SgZEwYFwfVQ@mail.gmail.com">
<div>
<div dir="auto">If we look at what record-like things look like
in other languages and settings (C structs, ML records, Pascal
records) accessors are the strange choice that needs
justification.</div>
</div>
</blockquote>
<blockquote type="cite" cite="mid:CAJuA9EiPbyf2NBqfFiuAndma0__A7vk60hz6N4-SgZEwYFwfVQ@mail.gmail.com">
<div>
<div>
<div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0px 0px 0px
0.8ex;border-left-width:1px;border-left-style:solid;padding-left:1ex;border-left-color:rgb(204,204,204)" dir="auto">In any case, the answer is simple: not all
objects are immutable. If a <br>
record component were an array, or an ArrayList, or any
other object <br>
with mutable state, having public fields would make it
impractical to <br>
use these types in records in many cases, because we'd be
unable to <br>
expose their state without also exposing their mutability.</blockquote>
<div dir="auto"><br>
</div>
<div dir="auto">I think you are suggesting techniques like
explicitly defining accessors for mutable record
components that make defensive copies? Are we really
comfortable calling records “a simple aggregation of
values” if I have to read the documentation or
implementation of an accessor just to understand what the
following code does:</div>
<div dir="auto"><br>
</div>
</div>
</div>
</div>
</blockquote>
<br>
This is exactly as we intended it to work. For records whose
components are values (e.g., `record Point(int x, int y) {}`), the
default implementation of constructor and accessor do exactly the
right thing, and no one has to write any code. But when mutability
rears its head, the "right thing" is less obvious, and making a
one-size-doesn't-fit-all decision will make some users unhappy. <br>
<br>
As it turns out, the mathematical construct from Domain Theory known
as "embedding-projection pairs" (which is a formalization of
approximation) offer us a useful way to talk about the right thing.
The key invariant that records must adhere to (specified in the
refined contract of `Record::equals`) is that unpacking a record
components, and repacking in a new record, should yield an "equals"
record:<br>
<br>
r.equals(new R(r.c0(), r.c1(), ..., r.cn())<br>
<br>
(This is as close as we can say in Java to "construction and
deconstruction form an embedding-projection pair between the space
of records and the cartesian product space of their components.") <br>
<br>
The reason that the situation you describe is inevitable comes from
the fact that for mutable components (such as arrays), in some cases
we want to judge two records equal if they hold the same _array
object_, and in other cases we want to judge two records equal if
they hold arrays _with the same contents_. And the language doesn't
know which you want -- and it requires very little imagination to
construct cases where each of these interpretations will be wrong.
So unless we're willing to outlaw records that are not immutable all
the way down, which would make records much less useful, we have to
give people a way to say what they want. This is just like how we
let map classes decide whether equals() means "same map", or means
"same mappings". Both are valid interpretations, and both should be
expressible. Similarly, some records may want to expose the
mutability of their components to clients, and others will want to
launder using defensive copies. All of these are expressible in the
record model, just with different degrees of explicit code. <br>
<br>
If your component already chooses the answer for equals that you
want -- such as ArrayList::equals comparing lists by contents, or
arrays comparing by identity -- then you can do nothing. Otherwise,
you have to override the constructor, accessor, and equals in
concert to preserve the invariant that deconstruction and
reconstruction yields something equivalent to the original. <br>
<br>
So if you define a record whose components are mutable, or for whom
you don't want the record equivalence semantics to be the same as
the component equals, you're going to have to write some code -- but
more importantly, you're going to have to tell your users what
equality means for *your* record. Just like you're supposed to
specify what equality means for every class. It might be tempting
to say "records are just structural tuples, so there's nothing
interesting to say about equality", but that turns out to be wishful
thinking. Consistent with the choice we've made elsewhere
(functional interfaces are nominal function types, not structural
ones; sealed types are nominal union types, not structural ones),
the rational choice for Java's product types is also nominal, not
structural. <br>
<br>
<br>
</body>
</html>