August 27, 2012
On 08/27/2012 01:16 PM, Artur Skawina wrote:
> On 08/27/12 12:54, Timon Gehr wrote:
>> On 08/27/2012 10:48 AM, Piotr Duda wrote:
>>> 2012/8/27 Walter Bright <newshound2@digitalmars.com>:
>>>> On 8/26/2012 11:14 PM, Piotr Duda wrote:
>>>>>
>>>>> Default args should be part of types (for passing them as template
>>>>> args etc, implicity convertable if they differs only on defaults) but
>>>>> not mangled in (since mangling is revelant only for linking, where
>>>>> defaults doesn't matter).
>>>>
>>>>
>>>> And then there's a list of other bugs that show up. Now you have two
>>>> different types showing up as the same type (i.e. name) to the linker, and
>>>> you've got weird collisions.
>>>
>>> For linker these types should be identical, so there shouldn't be any
>>> collisions, unless D handles default args fundamentally different than
>>> C++.
>>>
>>
>> You said they should be part of the type for passing as template args:
>>
>> auto foo(T)(T dg){
>>      return dg();
>> }
>>
>> // therefore
>> assert(foo((int x=2)=>x)==2); // this instantiation
>> assert(foo((int x=3)=>x)==3); // must differ from this one
>> // ergo, they cannot have the same mangled symbol name!
>
> Anonymous functions must be unique anyway.
>
> artur
>

What is the point?

August 27, 2012
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.


August 27, 2012
On Monday, August 27, 2012 11:38:52 Manu wrote:
> On 27 August 2012 11:12, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
> > and it makes no sense to use them with function pointers or function literals.
> 
> If that were true, we wouldn't be having this discussion.

You can't possibly really be using these functions with default arguments unless you're not really using them like function pointers, otherwise you wouldn't have been using the default arguments in the first place. Sure, you could have something like

auto func = (string a = "hello") { return a; }

and then call it with one argument or no argument, but that's only because the function is completely local, and you could just as easily do

string func(string a = "hello") { return a; }

and get the same thing. As soon as you've really used it as a function pointer rather than a local function, you've lost the default argument.

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
August 27, 2012
On 27 August 2012 13:54, Jonathan M Davis <jmdavisProg@gmx.com> wrote:

> On Monday, August 27, 2012 11:38:52 Manu wrote:
> > On 27 August 2012 11:12, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
> > > and it makes no sense to use them with function pointers or function literals.
> >
> > If that were true, we wouldn't be having this discussion.
>
> You can't possibly really be using these functions with default arguments unless you're not really using them like function pointers, otherwise you wouldn't have been using the default arguments in the first place.


How do I use a function pointer 'like a function pointer' by your reasoning?
Is dynamic linkage not a valid use of function pointers?
It's possibly the *most* common use. Shared code is not exactly uncommon,
just that it's often automated with compiler sugar these days.
Manually binding dynamic code has become rare, but it's still valid.


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.


Clearly, since it's a function pointer, I don't own the function its self,
or I'd just call that directly.
However, as you say, at the declaration point of the function pointer, I
can likewise inform the compiler of the default args.
If the default args were worked into the variable declaration, that might
work just as well as if it were in the type.

I don't really care so much HOW it works, only that it does. I think 99% of my cases would be addressed by the def args living in the variable declaration.


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

I agree, in principle, but I've still lost a thoroughly useful feature.
Move it perhaps (to the declaration?), but don't *re-*move it (cough).


August 27, 2012
On Monday, 27 August 2012 at 10:32:28 UTC, Manu wrote:
>> Because the two types were considered to be the same, only different.
>
> And how was that a problem? They never interacted in the example, the
> assignments were totally separate, they shouldn't have been confused.
> Just speculating, but it just looks like the type was misrepresented when
> it was looked up from a map by name or something, and matched the wrong
> cached definition... or something along those lines.
> It looks like a bug exposed from implementation detail, I can't see
> anything in the bug report that shouldn't theoretically work fine.

I seem to recall I looked at this issue myself at one point. It goes something like:
----
auto foo = (int a = 1) { return a; };
auto bar = (int a) { return a; };
----
int function(int) is mangled exactly the same as int function(int = 1) as default args aren't used for mangling. dmd does semantic analysis on the type of foo, which returns int function(int = 1), which is mangled as int function(int) and stored in dmd's hashmap of types (default args aren't mangled). When the semantic analysis of bar is done it checks the hashmap, sees that the type is already there (has the same name mangling) and does not repeat semantic analysis. If you switch the order of declarations then the opposite happens - the default arg is ignored.
August 27, 2012
On 08/27/2012 12:32 PM, Manu wrote:
> On 27 August 2012 11:28, Walter Bright <newshound2@digitalmars.com
> <mailto:newshound2@digitalmars.com>> wrote:
>
>     On 8/27/2012 1:08 AM, Manu wrote:
>
>
>         Also, I think it could be fixed so the scenario in the bug
>         report worked as
>         expected (I still don't understand why it did't work in the
>         first place).
>
>
>     Because the two types were considered to be the same, only different.
>
>
> And how was that a problem? They never interacted in the example, the
> assignments were totally separate, they shouldn't have been confused.
> Just speculating, but it just looks like the type was misrepresented
> when it was looked up from a map by name or something, and matched the
> wrong cached definition... or something along those lines.
> It looks like a bug exposed from implementation detail, I can't see
> anything in the bug report that shouldn't theoretically work fine.
> ...

+1.

August 27, 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.

Yes, I am suggesting that to get the default you want you define a new (free at runtime) type. You need the D declaration of whichever C struct anyway, so this is that declaration with a default added. In a more complex situation aliasing can be used. For e.g. doubles, you can play a suitable struct game for once and for all, and use it repeatedly inside the D version of C structs. And I am suggesting the language definition be changed to allow calls of function pointers be made with some trailing arguments omitted.

If default arguments for function pointers are not available, except for the default defaults (.init), then what of this proposal?



August 27, 2012
On 08/27/2012 02:48 PM, Robert Clipsham wrote:
> On Monday, 27 August 2012 at 10:32:28 UTC, Manu wrote:
>>> Because the two types were considered to be the same, only different.
>>
>> And how was that a problem? They never interacted in the example, the
>> assignments were totally separate, they shouldn't have been confused.
>> Just speculating, but it just looks like the type was misrepresented when
>> it was looked up from a map by name or something, and matched the wrong
>> cached definition... or something along those lines.
>> It looks like a bug exposed from implementation detail, I can't see
>> anything in the bug report that shouldn't theoretically work fine.
>
> I seem to recall I looked at this issue myself at one point. It goes
> something like:
> ----
> auto foo = (int a = 1) { return a; };
> auto bar = (int a) { return a; };
> ----
> int function(int) is mangled exactly the same as int function(int = 1)
> as default args aren't used for mangling. dmd does semantic analysis on
> the type of foo, which returns int function(int = 1), which is mangled
> as int function(int) and stored in dmd's hashmap of types (default args
> aren't mangled). When the semantic analysis of bar is done it checks the
> hashmap, sees that the type is already there (has the same name
> mangling) and does not repeat semantic analysis. If you switch the order
> of declarations then the opposite happens - the default arg is ignored.

If the compiler design *requires* equal types to be stored uniquely in
a hash map, then the default args shouldn't be stored as part of the
type in the AST. I assume it is rather inconvenient to fix, but
certainly possible.
August 27, 2012
I think that the function type and its mangled name must not contain the default args, then I can agree with Walter at the point.

But, I think the variables of function pointers and delegates still
can have default args as a part of their declarations.
(It will be a part of VarDeclaration, not a part of TypeFunction)
In following case, the default arg looks like a part of the type, but
actually is a part of the declaration of fp.

void function(int n = 10) fp;
pragma(msg, typeof(fp));  // should print void function(int), because
default args are not a part of type.
fp();  // I think this can be allowed, because fp can remember that
the first parameter has the default argument.

But, it seems to me there are some corner cases.

  // fp will *inherit* default args from its initializer, or not?
  auto fp = (int n = 10){}

  // what is the actual default arg of fp?
  void function(int n = 10) fp1 = (int n = 20){}
  void function(int n) fp2 = (int n = 30){}
  void function(int n = 40) fp3 = (int n){}

  // fp has ambiguous default arg, or has no default arg?
  auto fp1 = some_runtime_condition ? (int n = 10){} : (int n = 20){} ;
  // more complicated case, first defarg is same, then it will be *inherited*?
  auto fp2 = some_runtime_condition ? (int n = 10, string s =
"hello"){} : (int n = 10, string s = "world"){} ;

  int function(int n = 10) fp;   // default arg of the first parameter is 10
  fp = (int n = 20){ return n; }  // function literal's default arg
will be ignored (in my opinion), is this expected?

  // returning function pointer/delegate type can have default args?
  int delegate(int n = 10) foo(int x) { ... }

If we can take agreements each other about them, it may be supported.

Kenji Hara

2012/8/27 Walter Bright <newshound2@digitalmars.com>:
> On 8/27/2012 1:08 AM, Manu wrote:
>>
>> Does the bug report actually demonstrate how it was causing anybody any
>> problems? It seemed a rather contrived scenario that just illustrated that
>> there
>> was a bug.
>
>
> It was probably reduced from a larger scenario. Reduced bugs usually look pretty twisted.
>
>
>> Also, I think it could be fixed so the scenario in the bug report worked
>> as
>> expected (I still don't understand why it did't work in the first place).
>
>
> Because the two types were considered to be the same, only different.
>
> ----------------------------------
>
> Please post a canonical example of how you use this, so we can think of an alternative.
August 27, 2012
On 27 August 2012 15:48, Robert Clipsham <robert@octarineparrot.com> wrote:

> I seem to recall I looked at this issue myself at one point. It goes something like:
> ----
>
> auto foo = (int a = 1) { return a; };
> auto bar = (int a) { return a; };
> ----
> int function(int) is mangled exactly the same as int function(int = 1) as
> default args aren't used for mangling. dmd does semantic analysis on the
> type of foo, which returns int function(int = 1), which is mangled as int
> function(int) and stored in dmd's hashmap of types (default args aren't
> mangled). When the semantic analysis of bar is done it checks the hashmap,
> sees that the type is already there (has the same name mangling) and does
> not repeat semantic analysis. If you switch the order of declarations then
> the opposite happens - the default arg is ignored.
>

Cached in a hashmap! precisely what I suspected (without knowing anything
about it) ;)
That explains why Walter keeps going on about the name mangling. It's all
clear.