Function pointers/delegates default args were stealth removed?

Steven Schveighoffer schveiguy at yahoo.com
Mon Aug 27 07:58:41 PDT 2012


On Mon, 27 Aug 2012 09:23:54 -0400, kenji hara <k.hara.pg at gmail.com> wrote:

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

I think the type of the function pointer and the type (and mangling) of  
the function are two separate types.  One is a function pointer, one is a  
function.

You only need to mangle the function, not the pointer type.

Consider this rough equivalent (not sure how to write the constraints):

struct callWithN(F, int n) if(F is a function which takes an int as its  
last arg)
{
    F funcptr;
    auto opCall(T...)(T t) if(T is equivalent to F's args)
    {
       return funcptr(t);
    }
    auto opCall(T...)(T t) if(T is equivalent to F's args, except for last  
int arg)
    {
       return funcptr(t, n);
    }
}

I think the above (with correct template constraints) is equivalent to  
defining a function pointer with a default integer argument.  Note that  
the function it points to has *nothing* to do with default args, and so  
should be mangled like any other function.

So I think the default args have to be part of the pointer type, just not  
the function type.

> void function(int n = 10) fp;
> pragma(msg, typeof(fp));  // should print void function(int), because
> default args are not a part of type.

No.  They are part of the function pointer type.

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

Yes, this should be equivalent to:

void function(int = 10) fp = (int n){};

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

compiler error. Even if it should be able to reassign a default arg 10 to  
a default arg 20 function pointer, allowing the above to compile would be  
extremely confusing, and there is no real reason to allow it.  Use the  
property of the function pointer that gets the function pointer type  
without the default params (see below).

>   void function(int n) fp2 = (int n = 30){}

30

>   void function(int n = 40) fp3 = (int n){}

40

>
>   // fp has ambiguous default arg, or has no default arg?
>   auto fp1 = some_runtime_condition ? (int n = 10){} : (int n = 20){} ;

Compiler error.  You can't define the type differently based on a runtime  
condition.

>   // 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"){} ;

Again, two different types.  Error.

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

I think actually, this should be a compiler error, but it would be a valid  
choice to make this simply ignore the secondary default arg.

Here is what I would like to happen:

Given two sets of default parameter tuples X and Y, where X is not a  
prefix of Y, and Y is not a prefix of X, a function pointer with default  
args X cannot be assigned from a function pointer with default args Y.
Given X and Y where X is a prefix of Y, a function pointer with default  
args Y can be assigned from a function pointer with default args X.   
However, the opposite will not be true.
However, we should define a function pointer property (e.g. funcptr) which  
gives naked access to the underlying function pointer.

So if you had fx with default args X, and fy with default args Y, and both  
pointed at functions with the same parameter types, then you could do:

fx.funcptr = fy.funcptr;
fy.funcptr = fx.funcptr;

If this is too complicated, then just allowing all functions with the same  
underlying function parameter types to be freely assignable also is a  
valid (but IMO more confusing) choice.

Given the above, I think it would be prudent to have the default args  
returnable via a property or a __traits command.  e.g.:

auto tupleOfDefaultArgs = fx.defargs;

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

Of course.  Default args are part of the pointer type.

-Steve


More information about the Digitalmars-d mailing list