August 29, 2012
On 2012-08-28 21:27, Robert Clipsham wrote:

> The body of the function has nothing to do with its type.

If I change the body of one of the functions the problem doesn't appear.

-- 
/Jacob Carlborg
August 29, 2012
On Tuesday, 28 August 2012 at 23:34:54 UTC, Carl Sturtivant wrote:
> 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.

Another, more conservative, approach would be for the compiler to regard the non-general functions in such a group created by my transformation to be always inlined, so the default parameters are always evaluated before the call. Then your interesting example would work the way you expect.


August 29, 2012
On 29 August 2012 04:31, Jonathan M Davis <jmdavisProg@gmx.com> wrote:

> 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.
>

I've conceded that I don't mind changing my code, if a satisfactory
alternative exists (it doesn't currently). Also, I'd like to have some
notice that I need to make some time to change the code, and the
opportunity to work it into my schedule.
Surely that's not unreasonable.


August 29, 2012
On Tuesday, 28 August 2012 at 20:33:50 UTC, 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); }
>
> 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.

Here is an additional implementation possibility for the minimal version where there are no new types. Parameters, e.g.:

void fun(int x, int function(int x, int y = 1) fun) {
//...
  j = fun(3); //alerts the compiler
//...
}

could be analogously compiled to behave similarly, because the default arguments are 'nearby'. Here's what the compiler could in effect produce from the above.

int fun(int x, int function(int x, int y) fun) {
  int function(int x) fun = function void(int x) { return fun(x, 1); }
//...
  j = fun(3);
//...
}

i.e. use local variables for the required specialized versions of the function.

Of course then the question of "how near is nearby?" needs a design decision.


August 29, 2012
On Wednesday, August 29, 2012 12:40:45 Manu wrote:
> I've conceded that I don't mind changing my code, if a satisfactory
> alternative exists (it doesn't currently). Also, I'd like to have some
> notice that I need to make some time to change the code, and the
> opportunity to work it into my schedule.
> Surely that's not unreasonable.

Ideally, something which is going to be deprecated is first scheduled for deprecation (and marked as such in both the changelog and documentation) and then later deprecated, giving programmer's time to change their code first. It almost always works that way with druntime and Phobos, but I don't think that we necessarily do as good a job with the compiler. Frequently the situation is that people on the newsgroup know fullwell that a feature is going to be deprecated (e.g. delete), but that's not well communicated outside of this group, and for some reason, the to-be-deprecated items just don't get deprecated even though it's been definitively decided that they will be at some point.

In this particular case, it was viewed as a bug fix, and bug fixes break code all the time (especially accepts-invalid bugs), so no effort was made to indicate that a feature was going away (i.e. it was viewed as feature being fixed rather than a feature going away, so no notification beyond the bugfix in the changelog was given). Obviously, this was not handled in the best way, as this thread has shown. But stuff that's actually viewed as being deprecated generally is handled much better.

- Jonathan M Davis
August 29, 2012
On Wednesday, 29 August 2012 at 07:00:06 UTC, Marco Leise wrote:
> 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.

I was talking about complexity added to _the language_ and its syntax - the part exposed to the user. I did not mean to imply anything about the compiler implementation of it. If what you say is true, it just shows that those features such as pure shouldn't have got the @ prefix in the first place.

Anyway, my main point was:
a. There already is popular demand for metadata.
b. We already have some of the desired syntax for it in the language
c. Once the facility is fully implemented and supports user defined annotations it could also be leveraged to implement default arguments as well.
August 29, 2012
On Tue, 28 Aug 2012 04:57:53 -0400, Don Clugston <dac@nospam.com> wrote:

> On 27/08/12 16:16, Steven Schveighoffer wrote:
>> On Sun, 26 Aug 2012 18:26:40 -0400, Manu <turkeyman@gmail.com> wrote:
>>
>>> I just updated to 2.60 and found errors throughout my code where function
>>> pointers default args no longer work.
>>> *Every single project* I've written in D, 5 projects, don't work anymore,
>>> including my projects at work.
>>
>> OK, I've read all the posts on this, and this is what I think would
>> solve the problem:
>>
>> 1. default parameters are part of the function pointer type, because a
>> function pointer has a type.
>> 2. The mangled name of the function that is assigned to that function
>> pointer does *not* have default parameters mangled in.  Only the
>> function pointer type has them.
>> 3. Since the default parameters are part of the type, but not defined by
>> the function it points to, you can use interchangeably functions of the
>> same type which define default parameters or not (or define different
>> ones).  The default parameters follow the function pointer variable.
>
> This sounds like sloppy thinking.
> I _think_ what you are saying is that there should be implicit conversions from one function pointer type, to any other that has the same basic declaration, but different default arguments.
>
> But then you get problems with IFTI.
> void foo( void function(int x), double) {}
> void foo( void function(int x), int) {}
>
> void function(int x = 10) bar;
>
> foo(bar, 5); // fails -- ambiguous. Both overloads match with implicit conversions.

First, I don't see IFTI anywhere in there.

Second, why is this a problem?  We already have oddities in terms of how implicitly converting one argument makes the interpretation of non-ambiguous arguments ambiguous.

I don't think it's sloppy, my logic is: we can already (I think) do this in library code, so why is it impossible for the compiler to figure out?

> But really, it seems to me that this whole feature is just syntax sugar for one special case of currying.

Probably.  But it is what it is -- a poorly implemented/designed language feature.  In most cases, we don't simply drop them without giving a replacement.  Examples: octal literals, complex numbers, scope classes.

-Steve
September 06, 2012
OK. I have finished working to implement it as a new pull request. https://github.com/D-Programming-Language/dmd/pull/1102

It contains several test suites that indicate which case is supported or not. https://github.com/D-Programming-Language/dmd/pull/1102/files#L6R1

Regards.

Kenji Hara

2012/8/29 Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org>:
> 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
September 06, 2012
On 9/6/12 11:15 AM, kenji hara wrote:
> OK. I have finished working to implement it as a new pull request.
> https://github.com/D-Programming-Language/dmd/pull/1102
>
> It contains several test suites that indicate which case is supported or not.
> https://github.com/D-Programming-Language/dmd/pull/1102/files#L6R1
>
> Regards.
>
> Kenji Hara

Thank you very much!

Andrei
September 12, 2012
On 6 September 2012 12:15, kenji hara <k.hara.pg@gmail.com> wrote:

> OK. I have finished working to implement it as a new pull request. https://github.com/D-Programming-Language/dmd/pull/1102
>
> It contains several test suites that indicate which case is supported or
> not.
> https://github.com/D-Programming-Language/dmd/pull/1102/files#L6R1


Awesome, thanks for this!
How far off is 2.61 likely to be?


2 3 4 5 6 7 8 9 10 11 12
Next ›   Last »