August 28, 2012
On 8/28/12 8:23 AM, Manu wrote:
> Well that's painful for a number of reasons..
> Other than the fact that I need to rewrite a bunch of code,

Walter and Kenji think breaking meaningful existing code is an overriding concern, and I ended up agreeing with them.

They will look into a solution that keeps your working code working.

This change of wind may as well turn a new page in the history of D :o).


Andrei
August 28, 2012
On Tuesday, 28 August 2012 at 06:53:15 UTC, Jacob Carlborg wrote:
> On 2012-08-27 22:53, Walter Bright wrote:
>
>> The language design requires a 1:1 mapping of mangling to types. Hence
>> the compiler design to use the mangling as a hashmap key of types. The
>> failure of that approach in this case points to a problem in the
>> language design, not a bug in the compiler.
>
> How does this then work when the body of the anonymous functions are different? How will they be identified?

The body of the function has nothing to do with its type.
August 28, 2012
Andrei Alexandrescu:

> This change of wind may as well turn a new page in the history of D :o).

<humor>Maybe as soon as the D1 branch stops getting bug fixes, Walter&Co will start a D3 branch where this small breaking change happens.</humor>

Bye,
bearophile
August 28, 2012
On Monday, 27 August 2012 at 00:44:54 UTC, Walter Bright wrote:
> On 8/26/2012 4:50 PM, Timon Gehr wrote:
>> On 08/27/2012 12:41 AM, Walter Bright wrote:
>>>
>>> The trouble for function pointers, is that any default args would need
>>> to be part of the type, not the declaration.
>>>
>>
>> They could be made part of the variable declaration.
>
> You mean part of the function pointer variable?
>
> Consider what you do with a function pointer - you pass it to someone else. That someone else gets it as a type, not a declaration. I.e. you lose the default argument information, since that is not attached to the type.

I think this is the right behavior too. Default arguments are IMHO just a compact way to write some simply related overloaded functions, e.g. thus:

  int sum(int x, int y = 1 ) { return x + y; }

is just a compact way to write

  int sum(int x, int y) { return x + y; }
  int sum(int x) { return sum(x, 1); }

and a function pointer refers to a single function, so overloading and default arguments are irrelevant to function pointers. It just so happens that the particularly simple overloading abbreviated by a function definition with default arguments is easily optimized by the compiler with only one function arriving at the linker: the most general one. And that's the one whose address is supplied if the unary & operator is applied to it.

So that's the problem with 'int sum(int x, int y = 1 ) ...' --- it's not one function under the interpretation above. So how could we interpret
  int function(int x, int y = 1) sum;
in the above interpretation? What's happening right now is that sum is considered to be a single function pointer, so we discard the default to get the most general function type much like the effect of unary & above. So the trouble with the supposed type 'int function(int x, int y = 1)' is that it is not one type, just as the function sum above is not one function.

[Speculation mode starts here.] So what if function pointer declarations with defaults are considered to define several function pointers and not just one. e.g. thus:

  int function(int x, int y = 1) sum;

could be taken by the compiler to mean

  int function(int x, int y) sum;
//all the rest call back the general function pointer
  int function(int x) sum = function sum(int x) { return sum(x,1); }

I haven't explored all of the ramifications of this, but it looks as if it solves quite a few problems without changing the type system, or affecting existing code. And there's a simple model of what's going on: overloading, just generalized slightly.

This may not be clean enough or general enough. But the basic point that something like 'int function(int x, int y = 1)' is a sequence of types is worth attention. A declaration using a sequence of types should produce a sequence of function pointers under this interpretation. Exactly how "sequence of types" and "sequence of pointers" should be wrapped up for best effect is then the language design decision to make. There are several other interesting ways to go, some involving getting more general and allowing other kinds of overloading with function pointer sequences, not just the special kind that comes from default arguments, but I'll stop here for now.




August 28, 2012
On Tuesday, 28 August 2012 at 18:52:13 UTC, Andrei Alexandrescu wrote:
> On 8/28/12 8:23 AM, Manu wrote:
>> Well that's painful for a number of reasons..
>> Other than the fact that I need to rewrite a bunch of code,
>
> Walter and Kenji think breaking meaningful existing code is an overriding concern, and I ended up agreeing with them.
>
> They will look into a solution that keeps your working code working.
>
> This change of wind may as well turn a new page in the history of D :o).

I replied to Walter just now with a way to get a clean mechanism to do this, that's consistent with the existing type system, and with function pointers working exactly as they do now.

Carl.


August 28, 2012
On 08/28/2012 10:33 PM, Carl Sturtivant wrote:
> On Monday, 27 August 2012 at 00:44:54 UTC, Walter Bright wrote:
>> On 8/26/2012 4:50 PM, Timon Gehr wrote:
>>> On 08/27/2012 12:41 AM, Walter Bright wrote:
>>>>
>>>> The trouble for function pointers, is that any default args would need
>>>> to be part of the type, not the declaration.
>>>>
>>>
>>> They could be made part of the variable declaration.
>>
>> You mean part of the function pointer variable?
>>
>> Consider what you do with a function pointer - you pass it to someone
>> else. That someone else gets it as a type, not a declaration. I.e. you
>> lose the default argument information, since that is not attached to
>> the type.
>
> I think this is the right behavior too. Default arguments are IMHO just
> a compact way to write some simply related overloaded functions, e.g. thus:
>
>    int sum(int x, int y = 1 ) { return x + y; }
>
> is just a compact way to write
>
>    int sum(int x, int y) { return x + y; }
>    int sum(int x) { return sum(x, 1); }
> ...

This interpretation is simply wrong.

import std.stdio, std.c.stdlib;

void* alloca20bytes(void* x = alloca(20)){ return x; }

// your suggested transformation:

/+void* alloca20bytes(void* x){ return x; }
void* alloca20bytes(){ return alloca20bytes(alloca(20)); }+/

// would break the caller:

void main(){
    auto x = (cast(int*)alloca20bytes())[0..5];
    x[] = 0;
    x[] += 2;
    writeln(x);
}
August 28, 2012
On 28 August 2012 21:52, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org>wrote:

> On 8/28/12 8:23 AM, Manu wrote:
>
>> Well that's painful for a number of reasons..
>>
>> Other than the fact that I need to rewrite a bunch of code,
>>
>
> Walter and Kenji think breaking meaningful existing code is an overriding concern, and I ended up agreeing with them.
>
> They will look into a solution that keeps your working code working.
>
> This change of wind may as well turn a new page in the history of D :o).


Wow, I didn't see that coming.

At very least, just put it on a deprecation schedule. I'm happy (perhaps even prefer) to use the alternative approach I've describe if those 2 issues are addressed in some way.


August 28, 2012
On Tuesday, 28 August 2012 at 21:40:01 UTC, Timon Gehr wrote:
> On 08/28/2012 10:33 PM, Carl Sturtivant wrote:
>> On Monday, 27 August 2012 at 00:44:54 UTC, Walter Bright wrote:
>>> On 8/26/2012 4:50 PM, Timon Gehr wrote:
>>>> On 08/27/2012 12:41 AM, Walter Bright wrote:
>>>>>
>>>>> The trouble for function pointers, is that any default args would need
>>>>> to be part of the type, not the declaration.
>>>>>
>>>>
>>>> They could be made part of the variable declaration.
>>>
>>> You mean part of the function pointer variable?
>>>
>>> Consider what you do with a function pointer - you pass it to someone
>>> else. That someone else gets it as a type, not a declaration. I.e. you
>>> lose the default argument information, since that is not attached to
>>> the type.
>>
>> I think this is the right behavior too. Default arguments are IMHO just
>> a compact way to write some simply related overloaded functions, e.g. thus:
>>
>>   int sum(int x, int y = 1 ) { return x + y; }
>>
>> is just a compact way to write
>>
>>   int sum(int x, int y) { return x + y; }
>>   int sum(int x) { return sum(x, 1); }
>> ...
>
> This interpretation is simply wrong.
>
> import std.stdio, std.c.stdlib;
>
> void* alloca20bytes(void* x = alloca(20)){ return x; }
>
> // your suggested transformation:
>
> /+void* alloca20bytes(void* x){ return x; }
> void* alloca20bytes(){ return alloca20bytes(alloca(20)); }+/
>
> // would break the caller:
>
> void main(){
>     auto x = (cast(int*)alloca20bytes())[0..5];
>     x[] = 0;
>     x[] += 2;
>     writeln(x);
> }

Function inlining or not in the presence of alloca calls and similar using the existing stack frame are problematic. If the first call was inlined by the compiler, that would un-break the "problem". I suggest that we simply define default arguments via the transformation I suggested, and regard
  void* alloca20bytes(void* x = alloca(20)){ return x; }
as broken. It's not compelling for a lot of reasons.

Of course there may be something else wrong with the transformation! Fire away.

August 29, 2012
On Wednesday, August 29, 2012 01:13:15 Manu wrote:
> On 28 August 2012 21:52, Andrei Alexandrescu
> 
> <SeeWebsiteForEmail@erdani.org>wrote:
> > On 8/28/12 8:23 AM, Manu wrote:
> >> Well that's painful for a number of reasons..
> >> 
> >> Other than the fact that I need to rewrite a bunch of code,
> > 
> > Walter and Kenji think breaking meaningful existing code is an overriding concern, and I ended up agreeing with them.
> > 
> > They will look into a solution that keeps your working code working.
> > 
> > This change of wind may as well turn a new page in the history of D :o).
> 
> Wow, I didn't see that coming.
> 
> At very least, just put it on a deprecation schedule. I'm happy (perhaps even prefer) to use the alternative approach I've describe if those 2 issues are addressed in some way.

The funny thing about that is that for the most part, language features which are supposed to be deprecated tend to just stick around instead of getting deprecated, meaning that people keep on using them, and that by the time they're actually deprecated, they'll break that much more code...

It's one thing to decide not to make a change becasue we don't want to break code. It's quite another to just keep putting it off to avoid breaking code. That just makes things worse when it finally happens.

- Jonathan M Davis
August 29, 2012
Am Mon, 27 Aug 2012 19:46:57 +0200
schrieb "foobar" <foo@bar.com>:

> The point was that there are _other_ motivating examples for annotations hence there's already popular demand for it. Which is why it's worth the added complexity to the language. In fact part of that complexity *already* exists in D syntax via built-in annotations (e.g @safe).

Properties are currently implemented as "strip off the @ and continue". They are mapped to storage class bit flags, like the others with no special code paths or data structures in place.

-- 
Marco