May 10, 2020
On Sunday, 10 May 2020 at 03:14:08 UTC, Timon Gehr wrote:
> I don't see any reason why the concept "multiple function arguments" should be separate from the concept "multiple tuple elements". It's a distinction without a difference and I think it is a design mistake.

But that would mean we need a way to prevent a tuple from unpacking automatically, wouldn't it?

Or do we only allow exactly one or no tuple in an argument list?


May 10, 2020
On Sunday, 10 May 2020 at 03:14:08 UTC, Timon Gehr wrote:
> On 09.05.20 19:07, Mark wrote:
>> but the syntax is extremely terse (*mytuple).
>
> def foo(x, y):
>     return x + y
>
> print(map(foo, [(1, 2), (3, 4)])) # without unpacking, does not work
>
> # manual unpacking, kind of not "extremely terse":
> print(list(map(lambda t: foo(*t), [(1, 2), (3, 4)])))

Hmmm, very good point.

The issue seems similar (at least in spirit) to that of implicit casting. Implicit casting is, in a sense, syntactic sugar, saving you from writing "cast(mytype) myval" all over the place. It's also a highly contentious issue; everyone seems to be have their opinion of the extent to which implicit casting is a good thing.
May 10, 2020
On 10.05.20 09:00, Panke wrote:
> On Sunday, 10 May 2020 at 03:14:08 UTC, Timon Gehr wrote:
>> I don't see any reason why the concept "multiple function arguments" should be separate from the concept "multiple tuple elements". It's a distinction without a difference and I think it is a design mistake.
> 
> But that would mean we need a way to prevent a tuple from unpacking automatically, wouldn't it?
> ...

It does not mean that, because there would be no "unpacking".

The way to think about it is that every function has precisely one argument:

def f(t):
    return t[0] + t[1]

Then there is syntactic sugar. The following definition

def f(a, b){
    return a + b

Would actually mean:

def f(t):
    (a, b) = t
    return a + b

I.e., multiple function arguments are a pattern to which you match a tuple. You can then call the function with a tuple:

t = (1, 2)
f(t)

f(1, 2) # means the same as f((1, 2))
        # just like f(t) is the same as f((t))
        # additional parentheses mean nothing

In the grammar, a function call would be a function followed by a standard parenthesized expression. You literally parse the same thing after a function call as when you encounter parentheses in an expression.

> Or do we only allow exactly one or no tuple in an argument list?
> 
> 

You would be able to match as many tuples as you like, e.g.:

def f(a, (b, c)):
    return a + b + c

print(f(1, (2, 3))) # 6

A parameter list is just a pattern to match an argument to.
May 10, 2020
On 10.05.20 14:06, Mark wrote:
> On Sunday, 10 May 2020 at 03:14:08 UTC, Timon Gehr wrote:
>> On 09.05.20 19:07, Mark wrote:
>>> but the syntax is extremely terse (*mytuple).
>>
>> def foo(x, y):
>>     return x + y
>>
>> print(map(foo, [(1, 2), (3, 4)])) # without unpacking, does not work
>>
>> # manual unpacking, kind of not "extremely terse":
>> print(list(map(lambda t: foo(*t), [(1, 2), (3, 4)])))
> 
> Hmmm, very good point.
> 
> The issue seems similar (at least in spirit) to that of implicit casting. Implicit casting is, in a sense, syntactic sugar, saving you from writing "cast(mytype) myval" all over the place. It's also a highly contentious issue; everyone seems to be have their opinion of the extent to which implicit casting is a good thing.

It's not really similar. The problem is that there are two different things that are actually the same but still formally require conversion between each other. It's busywork without a justification.

Consider the following analogy. Let's say we introduce a new built-in type `Int` to D. It behaves precisely the same as `int`, but values of type `int` and type `Int` are incompatible. Do you think that's a good idea? Do you think that instead just not doing so raises any of the concerns around implicit casting? Do you think anyone would argue e.g. Rust has too liberal implicit casting because they do not have this kind of equivalent yet incompatible built-in types?
May 10, 2020
On Saturday, 9 May 2020 at 03:04:45 UTC, Walter Bright wrote:
> Keep in mind that as of recently, AliasSeq!(1,2,3) generates a tuple directly without going through the template instantiation mechanism.

Nice. I still think a builtin syntax including pattern matching is needed, though.
May 10, 2020
On Sunday, 10 May 2020 at 17:47:12 UTC, Timon Gehr wrote:
> On 10.05.20 09:00, Panke wrote:
>> [...]
>
> It does not mean that, because there would be no "unpacking".
>
> The way to think about it is that every function has precisely one argument:
>
> [...]

Yup! Tuples just like in mathematics! +1
May 10, 2020
On Sunday, 10 May 2020 at 17:56:22 UTC, Timon Gehr wrote:
> On 10.05.20 14:06, Mark wrote:
>> On Sunday, 10 May 2020 at 03:14:08 UTC, Timon Gehr wrote:
>>> On 09.05.20 19:07, Mark wrote:
>>>> but the syntax is extremely terse (*mytuple).
>>>
>>> def foo(x, y):
>>>     return x + y
>>>
>>> print(map(foo, [(1, 2), (3, 4)])) # without unpacking, does not work
>>>
>>> # manual unpacking, kind of not "extremely terse":
>>> print(list(map(lambda t: foo(*t), [(1, 2), (3, 4)])))
>> 
>> Hmmm, very good point.
>> 
>> The issue seems similar (at least in spirit) to that of implicit casting. Implicit casting is, in a sense, syntactic sugar, saving you from writing "cast(mytype) myval" all over the place. It's also a highly contentious issue; everyone seems to be have their opinion of the extent to which implicit casting is a good thing.
>
> It's not really similar. The problem is that there are two different things that are actually the same but still formally require conversion between each other. It's busywork without a justification.

They're not strictly the same. Consider the following function calls:

foo(1, 2, 3)
foo((1, 2, 3))
foo((1, 2), 3)
foo(1, (2, 3))
foo((1), (2), (3))
etc.

Maybe you intend for tuples to automatically "flatten" in the context of a function argument list (that is, all of the above expressions would be equal to foo(1, 2, 3)). This is a valid design decision but notably this is very different from how array and struct literals work. If the signature of foo were

void foo(int[2], int[1]);

then foo([1,2],[3]) is accepted, but foo([1],[2, 3]) is rejected. This is the kind of "implicit casting" I'm talking about.
May 10, 2020
On 10.05.20 22:59, Mark wrote:
> On Sunday, 10 May 2020 at 17:56:22 UTC, Timon Gehr wrote:
>> On 10.05.20 14:06, Mark wrote:
>>> On Sunday, 10 May 2020 at 03:14:08 UTC, Timon Gehr wrote:
>>>> On 09.05.20 19:07, Mark wrote:
>>>>> but the syntax is extremely terse (*mytuple).
>>>>
>>>> def foo(x, y):
>>>>     return x + y
>>>>
>>>> print(map(foo, [(1, 2), (3, 4)])) # without unpacking, does not work
>>>>
>>>> # manual unpacking, kind of not "extremely terse":
>>>> print(list(map(lambda t: foo(*t), [(1, 2), (3, 4)])))
>>>
>>> Hmmm, very good point.
>>>
>>> The issue seems similar (at least in spirit) to that of implicit casting. Implicit casting is, in a sense, syntactic sugar, saving you from writing "cast(mytype) myval" all over the place. It's also a highly contentious issue; everyone seems to be have their opinion of the extent to which implicit casting is a good thing.
>>
>> It's not really similar. The problem is that there are two different things that are actually the same but still formally require conversion between each other. It's busywork without a justification.
> 
> They're not strictly the same. Consider the following function calls:
> 
> foo(1, 2, 3)
> foo((1, 2, 3))
> foo((1, 2), 3)
> foo(1, (2, 3))
> foo((1), (2), (3))
> etc.
> 
> Maybe you intend for tuples to automatically "flatten" in the context of a function argument list (that is, all of the above expressions would be equal to foo(1, 2, 3)).

No, that would be terrible.

> This is a valid design decision but notably this is very different from how array and struct literals work. If the signature of foo were
> 
> void foo(int[2], int[1]);
> 
> then foo([1,2],[3]) is accepted, but foo([1],[2, 3]) is rejected. This is the kind of "implicit casting" I'm talking about.

Well, I think this is a bad idea and I did not suggest it.
1 2 3
Next ›   Last »