August 28, 2012
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?

-- 
/Jacob Carlborg
August 28, 2012
On 8/27/2012 11:53 PM, Jacob Carlborg wrote:
> How does this then work when the body of the anonymous functions are different?
> How will they be identified?

I don't know what you mean.


August 28, 2012
On 2012-08-28 09:16, Walter Bright wrote:

> I don't know what you mean.

The original problem in the bug report looked like this:

void main ()
{
    auto foo = (int a = 1) { return a; };
    auto bar = (int a) { return a; };

    writeln(foo());
    writeln(bar());
}

If I change one of the bodies of the anonymous functions to look like this:

void main ()
{
    auto foo = (int a = 1) { return a; writeln("foo"); };
    auto bar = (int a) { return a; };

    writeln(foo());
    writeln(bar());
}

It behaves correctly and won't compile any more.

-- 
/Jacob Carlborg
August 28, 2012
On 2012-08-27 23:28, Jonathan M Davis wrote:

> Except that the change which is causing Manu problems _isn't_ a new feature.
> It's a bug fix. So, better versioning wouldn't necessarily have helped him any
> at all. At best, if we had a more complex versioning scheme, it could be
> decided that the bug fix was potentially disruptive enough that it should only
> be fixed in a more major release, but _every_ bug fix risks breaking code,
> especially when code could be relying on the buggy behavior.

The fix for this particular bug was to remove a language feature. I don't think it would be wise to put that change in a minor release. It doesn't matter why the feature was removed. If a feature is remove from the language it should only be put in a major release, period.

-- 
/Jacob Carlborg
August 28, 2012
On 2012-08-27 23:29, Manu wrote:

> Are you suggesting using DLL's is asking for trouble? Dynamic linkage is
> a fundamental part of software.

Yes, they don't properly work in D.

-- 
/Jacob Carlborg
August 28, 2012
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.


But really, it seems to me that this whole feature is just syntax sugar for one special case of currying.
August 28, 2012
On Monday, 27 August 2012 at 21:29:06 UTC, Jonathan M Davis wrote:
> On Monday, August 27, 2012 23:22:39 foobar wrote:
>> All true, except one crucial fact: DMD gets critical bug fixes
>> incorporated with new features in the same release. This leaves a
>> poor choice to the programmer, either he sticks with older
>> compiler version and can't get any critical bug fixes, or he
>> updates the compiler to latest version with all the bug fixes but
>> risks breakage of code due to new features (which is _exactly_
>> what happened to manu).
>
> Except that the change which is causing Manu problems _isn't_ a new feature.
> It's a bug fix. So, better versioning wouldn't necessarily have helped him any
> at all. At best, if we had a more complex versioning scheme, it could be
> decided that the bug fix was potentially disruptive enough that it should only
> be fixed in a more major release, but _every_ bug fix risks breaking code,
> especially when code could be relying on the buggy behavior.
>
> - Jonathan M Davis

I guess your definition of stable is different than mine.
"Accepts invalid" bugs should never be fixed on the current stable branch as they introduce a breaking change unless it's a matter of a security problem.

All compilers have a list of accepts invalid bugs and no one "fixes" them on the stable/release branch exactly because it will break existing code as evidently shown by manu's posts.
Python introduced version 3 to handle this and Ruby had version 1.9, all the while both the stable and the next-version branches got bug-fixes.

D was moved to Git long ago which trivially allows such branching schemes so there really no excuse to stick with the current flawed system except inertia.
August 28, 2012
"Jonathan M Davis" <jmdavisProg@gmx.com> wrote in message news:mailman.1446.1346070222.31962.digitalmars-d@puremagic.com...
>
> Default arguments just do not make sense with function pointers, because
> they
> don't follow the function pointer, because it's a _pointer_ and has no
> knowledge of what it's pointing to. It's only at the declaration point of
> the
> function that the default argument exists, and that has _nothing_ to do
> with
> the function pointer. You might as well ask a reference of type Object
> what
> the arguments used to construct the derived class that it actually refers
> to
> were as expect a function pointer to have any clue about default arguments
> to
> the function that it points to.
>
> - Jonathan M Davis

Yes, this.  I looked into fixing issue 3866 earlier this year, and Kenji's list sounds very familiar.

It comes down to - function pointers are not function declarations and therefore can't do everything function declarations do, such as overloading and default arguments.  This is the price of being able to reassign them.

Yes it is possible to make them work the way Manu has been using them, but the solution is messy and I seriously doubt it's worth it.  I agree with everything Andrei has said about this.

I don't consider putting default arguments back in the type a valid approach because of the reason above, so that leaves giving function pointer variables the ability to have default arguments.  This seems to me like a really dumb corner case with the same problems.


August 28, 2012
On 28 August 2012 16:50, Daniel Murphy <yebblies@nospamgmail.com> wrote:

> "Jonathan M Davis" <jmdavisProg@gmx.com> wrote in message news:mailman.1446.1346070222.31962.digitalmars-d@puremagic.com...
> >
> > Default arguments just do not make sense with function pointers, because
> > they
> > don't follow the function pointer, because it's a _pointer_ and has no
> > knowledge of what it's pointing to. It's only at the declaration point of
> > the
> > function that the default argument exists, and that has _nothing_ to do
> > with
> > the function pointer. You might as well ask a reference of type Object
> > what
> > the arguments used to construct the derived class that it actually refers
> > to
> > were as expect a function pointer to have any clue about default
> arguments
> > to
> > the function that it points to.
> >
> > - Jonathan M Davis
>
> Yes, this.  I looked into fixing issue 3866 earlier this year, and Kenji's list sounds very familiar.
>
> It comes down to - function pointers are not function declarations and therefore can't do everything function declarations do, such as overloading and default arguments.  This is the price of being able to reassign them.
>
> Yes it is possible to make them work the way Manu has been using them, but the solution is messy and I seriously doubt it's worth it.  I agree with everything Andrei has said about this.
>
> I don't consider putting default arguments back in the type a valid
> approach
> because of the reason above, so that leaves giving function pointer
> variables the ability to have default arguments.  This seems to me like a
> really dumb corner case with the same problems.
>

Well that's painful for a number of reasons.
Other than the fact that I need to rewrite a bunch of code, I can't
actually produce a solution that works as well in lieu of some feature
requests.

A language feature should be deprecated for some time before it is surprise-removed like that... that would allow some time to discuss and possibly implement support for work-arounds.

Since I'll need to create wrapper functions and stubs for *everything*, I
really need __forceinline, or debug builds will really suffer. (That said,
I need it anyway for heaps of other stuff (SIMD in particular), but this
really seals the deal.)
Without it, all function calls require call-through stubs, all my API calls
become double-calls, and debugging becomes really tedious (stepping into
and out of stubs generated by magic that don't really exist every time you
press F11 >_<).

Also, in my case, I really need to be able to forward declare a function in
the same file as it is defined.
The user needs to write the prototypes, and then magic can scan for the
prototypes and generate the stub its self, but they can't currently appear
in the same file like in C/C++.

Without both of those things, my new solutions will be worse. More verbose, difficult to read&maintain, slower, and really annoying to debug.


Why are you so against default arguments associating with a declaration?
Why is the solution messy?
Default arguments simplify code. If a default is used frequently, it's
better to define it in one place, that is easy to change, and appears with
the definition. It's self-documenting, and very convenient.


August 28, 2012
On Monday, 27 August 2012 at 12:14:30 UTC, Manu wrote:
> On 27 August 2012 14:08, Carl Sturtivant <sturtivant@gmail.com> wrote:
>
>>
>>> extern(C) void function( ref const(Vector2) v0, ref const(Vector2) v1,
>>> ref const(Vector2) v2, ref const(Color) color = Color.white, BlendMode
>>> blendMode = BlendMode.Disabled ) fillTriangle2D;
>>>
>>
>> If function pointers could be called with fewer than the prototypical
>> number of arguments, and the remaining arguments be always initialized to
>> their .init defaults, you could perhaps make this sort of thing work
>> without the default argument values by using struct defaults.
>>
>> How would that be deficient?
>>
>
> ... no.
> Color does not .init == Color.white. You're suggesting I define a new type,
> obscuring the API, every time I want a non-.init default arg?
> Also, I think it's correct that functions shouldn't be callable without
> explicit parameters. Default args are carefully selected, and they are
> always opt-in.
> 'v2' in this case shouldn't be allowed to default to [ NaN, NaN ] if I omit
> it.

More specifically, you can get the default initialization of e.g. double to be different as follows.

import std.stdio;

struct dbl(double init) {
    double d = init;
    alias d this;
}

void main() {
	dbl!3.142 x;
	dbl!2.0 y;
	writeln(x*y);
}

In the case of an external(C) struct, the D definition can fix up its own default initialization without a new type name even. Color for example could be fixed up to initialize to Color.white by default.

And, having the compiler fix up omitted trailing arguments with .init default values could be confined to "opt-in" parameters by a small change to the type system for function pointers as follows.

The type of a function pointer could now include the number of trailing parameters that may be defaulted. This does not explode the size of a mangled name much. A syntactic mechanism to indicate which trailing parameters may be defaulted in a function prototype could be added to D. The default would be none with functions declared without that mechanism. This mechanism needs to be a part of the prototype so that it can be used on external(C) functions etcetera.

Now only trailing parameters that you intend to be defaulted would would get defaulted with the .init treatment. Others would be compilation errors.

Now what's wrong with this if there are no trailing argument defaults except for the .init defaults?