manifold
manifold copied to clipboard
[Feature] Add support for tuple destructuring
Is your feature request related to a problem? Please describe. Consider the following method:
auto returnTuple() {
return "foo", 42, 13.37, (LocalDateTime.now());
}
When you want to use specific components of this tuple, it becomes quite verbose:
var tupleItems = returnTuple();
// You'll have to use the item1, item2, etc. to access the items
String s = tupleItems.item1;
int i = tupleItems.item2;
double d = tupleItems.item3;
LocalDateTime ldt = tupleItems.item4;
System.out.println("s = $s, i = $i, d = $d, ldt = $ldt");
// or directly, which makes the line a bit longer
System.out.println("s = ${tupleItems.item1}, i = ${tupleItems.item2}, d = ${tupleItems.item3}, ldt = ${tupleItems.item4}");
Describe the solution you'd like It would be nice if manifold supported tuple destructuring, like so:
var (s, i, d, ldt) = returnTuple();
System.out.println("s = $s, i = $i, d = $d, ldt = $ldt");
This would also be a nice feature for interacting with records, when you want to more formally define and document the data structure. Consider this:
/**
* This describes a person
*
* @param name name of person
* @param age age of person
*/
record Person(
String name,
int age
) {}
...
String doSomethingWithPerson(PersonSupplier personSupplier) {
var (name, age) = personSupplier.getPerson();
return "$name is $age years old";
}
In the case that the tuple/record has more items than the destructuring requests, the extra items should be ignored. Maybe _ could be used for explicitly ignoring/skipping certain elements during destructuring, like so:
var (s, _, d) = returnTuple();
System.out.println("s = $s, d = $d");
Describe alternatives you've considered The syntax could also be like this for when you don't want to use type inference:
(String s, int i, double d, LocalDateTime ldt) = returnTuple();
Destructuring classes in general would technically also be possible, but would be way more complex and therefore out of scope, due to having to decide which fields/methods to make available as items, inheritance and an unclear ordering of the items. Records are straight-forward: they have no inheritance, all items are specified as record parameters, in a specific order and they have a getter by default.
Additional context See documentation for tuple deconstructing/destructuring in other languages:
- C#: https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/deconstruct
- Kotlin: https://kotlinlang.org/docs/destructuring-declarations.html
JEP for java 21 for destructuring records when using instanceof: https://openjdk.org/jeps/440
preview JEP for java 21 for unnamed patterns and variables: https://openjdk.org/jeps/443
PS: why are the extra brackets needed around LocalDateTime.now()? It doesn't compile without them.
Hi @CC007. All great feature requests.
Regarding, the LocalDateTime.now() question, I'm not seeing that.
auto returnTuple() {
return "foo", 42, 13.37, LocalDateTime.now();
}
Works fine for me, both in IJ editor & compilation.
I'm getting this:
So without brackets compiles alright, but the item isn't usable as item4.
It got compiled to this instead:
As you can see, it is compiled to now instead item4.
Right. That is intentional. Tuples infer labels from the expressions if possible. In this case the method name.
It is a bit unintuitive though that item4 couldn't be used as well as an alias.
It is a bit unintuitive though
Yep. But I think label inference tends to be more useful than not because:
-
Code completion.
I would think the vast majority of manifold users are developing with IJ / Android where the tuple items are at your fingertips. -
Explicit labels.
Unless the labels are apparent from the expressions (refs to fields, locals, properties, etc.) direct labels are best. -
Low arity.
Most tuples consist of two items. If you’re using tuples, you probably like labeling your two items explicitly, otherwise you’d probably prefer a ‘Pair’ class or the like. Just my take on it.
Those are indeed all good reasons why label inference is intuitive to have. What I found unintuitive though was not that there is inference, but the lack of the item4. I'm a proponent of having both.
Sure, that makes sense. Always have the itemN syntax regardless of the labels. I like it.
Would be interesting to make array operator work where a compile-time constant index expression would determine the type:
String item1 = tuple[0];
int item2 = tuple[1];
lol
Agreed. Actually wanted to add that as a feature request too, but considering the type differences, I could see that being an issue.
Any progress on implementing this feature?