Multiple return values

forax at forax at
Mon Jan 14 20:49:19 UTC 2019

----- Mail original -----
> De: "Brian Goetz" <brian.goetz at>
> À: "Remi Forax" <forax at>
> Cc: "Lukas Eder" <lukas.eder at>, "amber-spec-experts" <amber-spec-experts at>
> Envoyé: Lundi 14 Janvier 2019 17:29:54
> Objet: Re: Multiple return values

> I was trying to keep my reply focused on concepts (nominal product types
> rather than tuples), rather than ad-hoc syntactic tricks (which have the
> risk of blurring the distinction.)

That's the point of my previous mail!, blur the distinction between a tuple and non mutable record, a tuple being just syntactic sugar one top of records and pattern matching.

> You're basically proposing several things:
>  - Define a distinguished sub-category of records that have extra features;
>  - For that sub-category, provide an ad-hoc, tuple-like construction
> syntax;
>  - For that sub-category, provide an ad-hoc, tuple-like destructuring
> syntax.
> I think the first is a mistake, and I don't think we really need either
> of the latter two -- and I think having them may well be more
> confusing.  If you're returning a Range, then saying
>     x -> new Range(x,x+10)
> is saying what you mean, and it's not very painful.

The first item is a mistake (re-reading it), but i think that ensuring that a tuple is non mutable is something important, but being a record and a value type is enough.

> Similarly, there's no need to have an ad-hoc destructuring syntax for
> records; we _already_ have that, which is pattern matching. Whatever the
> syntax of "unconditional bind" is going to be, you'd be able to say
> something like
>     __unconditional_bind Range(var lo, var hi) = getRange(...)
> with an ordinary destructuring pattern.  No need for an explicit
> pseudo-tuple concept, and no need for an ad-hoc tuple-like destructuring
> mechanism.

yes, i fully agree, it's just syntactic sugar on top of records and pattern matching.
That's what's make the proposal great and stupid at the same time.
It's great because it's just syntactic sugar and it's stupid because it's just syntactic sugar, and like any syntactic sugars it can make the code less readable because it carries an implicit semantics.

> If, at the end of the game, we decide that the straight denotation of
> pattern matching isn't enough, we can revisit. 

yes !

> If, at the end of the game, we decide that the straight denotation of
> pattern matching isn't enough, we can revisit.  But the answer to Lukas'
> question is basically:
>  - Multiple return is a weak feature, that will feel like tuples
> dangled in front of your face, and then snatched back;
>  - We prefer nominal tuple (records) to structural ones;
>  - Records will have a compact (usually one line) declaration, a
> compact construction syntax, and a compact destructuring syntax.

Yes, i've hijack this thread a little, i fully agree with your point 1 and 3.
I'm not sure about your point 2, yes, the Java type system is nominal, but sometimes a structural syntax help readability, lambdas is a good example.
Anyway, as you said, we can revisit that later.


> On 1/14/2019 6:20 AM, Remi Forax wrote:
>> You can have both !
>> This is basically what we are doing with lambdas, you have a structural syntax +
>> a named type that are bound together using inference.
>> Let say we have a tuple keyword that means, value + record +
>> constructor/de-constructor
>>    tuple Range(int lo, int hi) { … }
>> then you can write:
>>    Range method(int x) {
>>      return (x, x + 1);  // the compiler infers "new Range(x, x + 1)"
>>    }
>> and also
>>    var (x, y) = method();  // the compiler uses the de-constructor or the record
>>    getters if there is no de-constructor
>> With Stream<???> s =, ??? is a Range,
>> and if someone want to use the tuple syntax inside a call to map(), a type as to
>> be provided,
>> by example
>>    aStream.<Range>map(x -> (x, x + 1)).collect(...)
>> Rémi
>> ----- Mail original -----
>>> De: "Brian Goetz" <brian.goetz at>
>>> À: "Lukas Eder" <lukas.eder at>
>>> Cc: "amber-spec-comments" <amber-spec-comments at>
>>> Envoyé: Vendredi 11 Janvier 2019 17:07:43
>>> Objet: Re: Multiple return values
>>> While I understand where you’re coming from, I think multiple return is likely
>>> to be both more intrusive and less satisfying than it first appears.
>>> First, it’s a relatively deep cut; it goes all the way down to method
>>> descriptors, since methods in the JVM can only return a single thing.  So what
>>> you’re really asking the compiler to do is create an anonymous record (whose
>>> denotation must be stable as it will be burned into client classfiles.)  That’s
>>> the “more intrusive” part.
>>> The “less satisfying” part is that if you can return multiple values:
>>>     return (x, y)
>>> and then obviously you need a way to destructure multiple values:
>>>     (x, y) = method()
>>> (since otherwise, what would you do with the return value?)
>>> But here’s where people will hate you: why can I use tuples as return values,
>>> and destructure them into locals, but not use them as method arguments, or type
>>> parameters?  Now I can’t compose
>>>     someMethod(method())
>>> because I can’t denote the return type of method() as a parameter type.  And I
>>> can use your multiple-returning method in a stream map:
>>>     Stream<T> s =   // stream of what?
>>> When we tug on this string, we’ll be very disappointed that it’s not tied to
>>> anything.
>>> Instead, what you can do is expose records in your APIs:
>>> ```
>>> class MyAPI {
>>>     record Range(int lo, int hi) { … }
>>>     Range method() { … }
>>> }
>>> ```
>>> and now a caller gets a Range back, which is a denotable type and whose
>>> components have descriptive names.
>>> You say you don’t want to do this because creating new types is so much work.
>>> Is the one-line declaration of `Range` above really so much work?  (Ignoring
>>> the fact that returning a Range is far more descriptive than returning an (int,
>>> int) pair.)
>>>> On Jan 11, 2019, at 10:57 AM, Lukas Eder <lukas.eder at> wrote:
>>>> Hello,
>>>> I'm referring to the exciting proposed new features around destructuring
>>>> values from records and other types as shown here:
>>>> The example given was:
>>>>   Rect r = ...
>>>>   __let Rect(var p0, var p1) = r;
>>>>   // use p0, p1
>>>> This is a very useful construct, which I have liked using in other
>>>> languages a lot. Just today, I had a similar use case where I would have
>>>> liked to be able to do something like this, but without declaring a nominal
>>>> type Rect. Every now and then, I would like to return more than one value
>>>> from a method. For example:
>>>>   private X, Y method() {
>>>>     X x = ...
>>>>     Y y = ...
>>>>     return x, y;
>>>>   }
>>>> I would then call this method as follows (hypothetical syntax. Many other
>>>> syntaxes are possible, e.g. syntaxes that make expressions look like
>>>> tuples, or actual tuples of course):
>>>>   X x, Y y = method();
>>>> The rationale is that I don't (always) want to:
>>>> - Modify either type X or Y, because this is just one little method where I
>>>> want to indicate to the call site of method() in what context they should
>>>> interpret X by providing a context Y
>>>> - Wrap X and Y in a new type, because creating new types is too much work
>>>> - Wrap X and Y in Object[] because that's just dirty
>>>> - Rely on escape analysis for some wrapper type (minor requirement for me)
>>>> - Assign both X and Y. Something like "X x, _ = method()" or "_, Y y =
>>>> method()" would be useful, too.
>>>> I was wondering if in the context of all the work going on in Amber around
>>>> capturing local variables, etc. if something like this is reasonably
>>>> possible as well in some future Java.
>>>> This is possible in Python. Go uses this syntax to return exceptions.
>>>> Thanks,
> >>> Lukas

More information about the amber-spec-experts mailing list