Proposal: Object/?? Destruction

Timon Gehr timon.gehr at gmx.ch
Thu Oct 12 19:05:35 UTC 2017


On 10.10.2017 17:05, Steven Schveighoffer wrote:
> On 10/9/17 11:22 AM, Timon Gehr wrote:
>> On 09.10.2017 01:20, Steven Schveighoffer wrote:
>>>
>>> My questioning comes with this:
>>>
>>> void bar(int a);
>>> void bar((int,) x);
>>>
>>> To me, it is confusing or at least puzzling that these two aren't the 
>>> same.
>>> ...
>>
>> Well, to me it is a bit confusing that this is puzzling to you. Why 
>> should int be the same as (int,)? It does not make sense to index an 
>> integer, but (int,) can be indexed with 0 to get an integer.
> 
> I understand why (int,) is different from int. What I meant was, why 
> can't I *call* a function that takes a single int tuple with a single 
> int value?
> ...

Because this would require a special-case rule that I had not considered 
so far. This is up to discussion though.

I interpreted your question to be: "Why do your proposed rules not lead 
to my expected behaviour?", and not: "Why do your rules not allow 
this?", but it seems I have misinterpreted your question. Sorry for the 
confusion! :)

> It shouldn't matter to the caller whether you plan to fiddle with your 
> parameter via tuple syntax or directly with a value.
> ...

I see. I think what you propose does make sense, as it might smoothen 
out the interaction with other D language features such as variadics and 
overloading.

> Again, I go back to the 2-parameter version. I can call it with 2 
> values, or a tuple of 2 values.

With the caveat that those two cases are actually identical, yes.

auto x = (1,"2"); // construct value
f(x); // now call f with value

and

f(1,"2"); // construct tuple and call f with the resulting value

It is like:

auto x = [1,2];
f(x);

and

f([1,2]);

Except that redundant parentheses are optional:
f(1,"2") is exactly equivalent to f((1,"2")) after parsing.

The second expression just adds an additional pair of parentheses around 
f. f(((1,"2"))) is also the same expression for the same reason.

Note that this does not compile:

void f(int a,int b,int c){}
f(1,(2,3));

The reason is that I tried to call f with an argument of type 
(int,(int,int)), while it expected an argument of type (int,int,int).

> It makes no difference to the callee how 
> I call it, as long as I put 2 values on the stack.
> ...

Well, I think it should maybe not be possible to conflate e.g. (int,int) 
and ((int,),(int,)).

> I don't see why it should be different for a single parameter function.
> ...

I think you are making a strong point here.

> To put it another way, in your scheme, what is the benefit to 
> overloading a single value function call with a function call that takes 
> a single element tuple? When would this be useful?
> ...

I agree that this is actually not useful.

Note that this means the following code will be accepted also:

void foo(int x,int y,int z){}

foo((1,2,3),);

Does this match your expectation?

>>> Currently, I can call this:
>>>
>>> foo(T...)(T t) if (T.length == 1) // function that takes a single 
>>> element tuple
>>>
>>> like this:
>>>
>>> foo(1);
>>>
>>> Why is this disallowed in your tuple scheme?
>>> ...
>>
>> I take this to mean, why does the following code not compile:
>>
>> void foo(T)(T t) if(T.length == 1) { ... }
>>
>> foo(1);
> 
> Nope, I meant my original. A "tuple" as D currently uses it, can have 
> exactly one element, and I can call that function with exactly one 
> value. I don't have to call it as:
> 
> AliasSeq!(int) v;
> v[0] = 1;
> foo(v);
> 
> Which is analogous to your requirements (obviously, D is missing the 
> syntax for tuple literals, which is why it's complicated).
> 
> Note that if foo is:
> 
> foo(int x);
> 
> I can still call it with v. I don't see why we can't keep these kinds of 
> allowances.
> ...

I see. Well, we can't keep them to the extent AliasSeq has them. 
AliasSeq always auto-expands. Auto-expansion for tuples can become a 
problem, especially in generic code, because it forgets structure 
information. For example:

void printElements(T)(T[] arr){
     foreach(x;enumerate(a)){
         print("at index ",x[0]," we have ",x[1]);
     }
}

auto a = [(1,2),(3,4),(5,6)];
printElements(a);

With auto-expansion, this prints:
at index 0, we have 1
at index 1, we have 3
at index 2, we have 5

However, it is quite clear from the definition of printElements that the 
programmer wanted it to print:

at index 0, we have (1,2)
at index 1, we have (3,4)
at index 2, we have (5,6)

AliasSeq does not have this specific problem, because it cannot be put 
into an array without expanding.

>>> I would think single value tuples and single values would be pretty 
>>> much interchangeable.
>>
>> Well, no. Otherwise 2[0] would be allowed and equal to 2. And then, 
>> what would [2][0] be? [2] or 2?
> 
> Not interchangeable in terms of usage, but interchangeable in terms of 
> overloading.
> 
> What I would have expected is for foo(int) and foo((int,)) to be 
> equivalent mangling (like the bar(int, int) and bar((int, int)) are 
> equivalent), and for the caller to be able to call those functions with 
> either a single value or a singleton tuple.
> 
> Inside the function, of course, they are treated differently as the 
> callee decides whether to unpack the tuple or not via the parameters.
> 

This makes sense, and I think your proposal improves the design.


More information about the Digitalmars-d mailing list