anonymous records as an implementation for tuples in Java

Remi Forax forax at univ-mlv.fr
Sat Dec 14 13:51:55 UTC 2024


> From: "Brian Goetz" <brian.goetz at oracle.com>
> To: "Red IO" <redio.development at gmail.com>
> Cc: "david Grajales" <david.1993grajales at gmail.com>, "amber-dev"
> <amber-dev at openjdk.org>
> Sent: Wednesday, December 11, 2024 6:27:13 PM
> Subject: Re: anonymous records as an implementation for tuples in Java

> I had thought my reminder in the last reply would be sufficient, but again: this
> is not the Java language design list, and "why don't you just" proposals like
> this just distract us from doing what we've actually prioritized.

> In the 30 seconds I could spare to look at your idea, it seems to have all the
> same problems as the C# anonymous class feature.

> As a side exercise, I invite you to ponder where $TString-int lives, when
> classes in two separate domains both use (String, int) and want to call each
> other, and what could go wrong there. (But not on this list.)
Is it not the same issue as when you have a deconstructor method in one class and a switch on it in another class ? 

class Foo { 
deconstructor (String s, int i) Foo { ... } 
... 
} 

Foo foo = ... 
switch(foo) { 
case Foo(String s, int i) -> ... 
} 

Rémi 

> On 12/11/2024 11:59 AM, Red IO wrote:

>> As tuples can be implemented entirely as synthetic sugar I don't see the
>> problem. Simply desugar all denotations of the tuple type to a structurally
>> named type similar to arrays. Then create 1 record definition for each used
>> type. (which I guess is at some point done for arrays)
>> Example:
>> (String, int) foo() {
>> return ("hi", 42);
>> }
>> void bar((String, int) tup) {
>> System.out.println(tup.0 + tup.1);
>> }

>> var x = foo();
>> bar(x);

>> Becomes:

>> public record $Tjava_lang_String-int(String e0, int e1) extends Tuple {}

>> $Tjava_lang_String-int foo() {
>> return new $Tjava_lang_String-int("hi", 42);
>> }

>> void bar($Tjava_lang_String-int tup) {

>> System.out.println(tup.e0() + tup.e1()) ;

>> }

>> var x = foo();
>> bar(x);

>> This is completely possible with preprocessing alone. Syntax, descriptor format
>> and named vs unnamed elements are details not worth the initial discussion.

>> I think tuples are great and require no fundamentally new features to become
>> part of the language.

>> Great regards

>> RedIODev

>> On Wed, Dec 11, 2024, 17:23 Brian Goetz < [ mailto:brian.goetz at oracle.com |
>> brian.goetz at oracle.com ] > wrote:

>>> Yes, this is one of those ideas that sounds good for the first few minutes. (C#
>>> has explored something similar with what they call "anonymous classes", which
>>> turned out to be mostly disappointing.)

>>> The problem is _linkage_. It's easy to write out the creation expression:

>>> var tuple = (int id: 10, String name: "foo")

>>> So now: what's the type of `tuple`? What can I assign it to? How do I extract
>>> the members? How do I write a method that accepts a tuple of (int id, String
>>> name)? What if someone passes it a tuple of (int x, String s)? What does equals
>>> and hashCode do on these things? These things have many potential answers, but
>>> none of them are very satisfying.

>>> If you're going to create a tuple, presumably someone wants to consume it, store
>>> it somewhere, extract its components. C#'s answer was that you can only do so
>>> _within a compilation unit_ (effectively, within the same class) because there
>>> was no guarantee that one classes { x: 1, y: 2 } was interoperable with
>>> another.

>>> Linkage in Java is nominal; when you call a method `m("foo")`, the caller and
>>> declaration have to agree on the types, and the method descriptor (in this
>>> case, `(Ljava/lang;String;)V`) is recorded in the classfile. if you want to be
>>> able to pass a tuple to a method, we have to record something, and that means
>>> either inventing a whole new structural type system to ensure that tuples of
>>> the wrong type don't get exchanged, or erasing everything to some "Tuple" class
>>> (in which case you lose names and likely types of components.)

>>> DISCLAIMER: this is not meant to be a canonical explanation of why we can't have
>>> it. It is literally the first 30 seconds of stuff off the top of my head about
>>> why this is more complicated, from the perspective of how the language holds
>>> together, than it looks.

>>> Essentially, this doesn't really give you the expressive power people want from
>>> tuples; what it gives you is a convenient syntactic shorthand for packing the
>>> elements into a blob. Which makes it a fairly weak feature, and one where, once
>>> we had it, people would immediately see its weaknesses and then want more. So
>>> it is not any kind of shortcut; it is mostly convincing ourselves that concise
>>> creation syntax is the only important thing we get from tuples. But I don't
>>> think that's a good idea.

>>> I would put this problem in the same bucket as "collection literals" --
>>> optimized syntactic forms for common structural shapes such as lists. This is
>>> on our radar but there are a number of higher-priority things ahead of it, so
>>> we won't be talking about it for a while.

>>> On 12/11/2024 10:58 AM, david Grajales wrote:

>>>> I've noticed that the topic of tuples in Java has come up recently, and I wanted
>>>> to take this opportunity to show an idea regarding the use of "anonymous"
>>>> records as a potential implementation for tuples.

>>>> The idea would be to create ad-hoc records on the fly for short lived methods,
>>>> which don’t have a formal name but are defined by their components. For
>>>> example, imagine something like this:

>>>> var tuple = ( int id: 10 , String name: "name" );

>>>> This would allow us to create simple, unnamed records with specified fields for
>>>> quick, on-the-fly usage. Accessing values from the tuple could then work like
>>>> this:

>>>> var myTupleId = [
>>>> https://urldefense.com/v3/__http://tuple.id__;!!ACWV5N9M2RV99hQ!JWvS3-XRXfU_BDrdY-5L5h1ddl_PStJP3vNDQtkLvrxFIdBwPvzjEW-LMmG4r8MykbGgC-Y4e8oBmPElPpwijXdqZiO2$
>>>> | tuple.id ] ()

>>>> for passing them as arguments to methods it could be something like this.

>>>> void foo(Tuple<Integer, String> tuple){}

>>>> The idea is that, as records are just classes with special constraints to force
>>>> invariants, tuples could be records with special constraints, for example as
>>>> they would be meant to be created on the fly for pin point needs, they should
>>>> not have validation in the constructor or overriding of getters, but they would
>>>> still get automatic equals() , hashCode() , and toString() methods.

>>>> I don't know how problematic or bad this approach would be if there were plans
>>>> to ever introduce construct tuples to Java.

>>>> best regards.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20241214/e1b7b559/attachment.htm>


More information about the amber-dev mailing list