Thread overview
Associative parameters
Jun 26, 2005
Chris Sauls
Jun 26, 2005
Sefan Zobel
Jun 27, 2005
Walter
Jul 10, 2007
Greg
Jul 10, 2007
Bill Baxter
Jul 10, 2007
Pragma
Jul 10, 2007
BCS
Jul 11, 2007
Bill Baxter
Jun 27, 2005
David Medlock
June 26, 2005
Okay... I vaguely remember this getting mentioned, either by myself, or Matthew, or some other D-ite with some Python experience, and then getting discussed briefly, and more-or-less forgotten...  Well, recently I found myself randomly loving it again, and decided to bring it up once more.  :)

In python, suppose a define a function, let's call it 'foo', and suppose it takes three paramters, let's call them 'x', 'y', and 'z'.  Now, ordinarily one would just call it in the usual way:

# foo( someX, someY, someZ )

But suppose, for some reason -- maybe the values look better this way, maybe it suits the overall style of the coder writing the call, whatever -- someone decides they'd like to pass them in a different order, or that they'd like to be explicit about what each parameter is (I've felt this way often with the Win32 API, for example, and usually go about it using comments).  In python, you would do something like this:

# foo (
#   x = someX ,
#   y = someY ,
#   z = someZ
#   )

Now isn't that just nifty?  So... given the following D function decleration:

# void myfunc (Cartesian grid, Point rectOrigin, Size rectSize, Translation action) {
#   // do stuff
# }

Wouldn't it be nice to be able to do something like... this:

# myfunc(
#   action     : Translation.Move(5, 10)       ,
#   rectOrigin : Point(p_rect.x, p_rect.y)     ,
#   rectSize   : Size(p_rect.w, p_rect.h)      ,
#   grid       : g_grid                        ,
# );

Now... isn't that descriptive?  :)  Naturally there would have to be strict rules.  Either A) make a given function call either associative or not, never both, or B) require that any non-associative parameters come first and be in proper order (which if I remember right, is what Python does).  Also it would, of course, have to be an error to pass a parameter twice.

I know I'm probably blowing smoke, but its something I'm fond of.  (The associative parameters, not the smoke.)

-- Chris Sauls
June 26, 2005
In article <d9lnrr$26q3$1@digitaldaemon.com>, Chris Sauls says...
> In python, you would do something like this:
>
># foo (
>#   x = someX ,
>#   y = someY ,
>#   z = someZ
>#   )
>
>Now isn't that just nifty?


This is also called "named parameters" in some languages (since parameters
are resolved by name, not by position). And, yes, I like it too :)

Best regards,
Stefan


June 27, 2005
"Sefan Zobel" <Sefan_member@pathlink.com> wrote in message news:d9n5i9$aad$1@digitaldaemon.com...
> In article <d9lnrr$26q3$1@digitaldaemon.com>, Chris Sauls says...
> > In python, you would do something like this:
> >
> ># foo (
> >#   x = someX ,
> >#   y = someY ,
> >#   z = someZ
> >#   )
> >
> >Now isn't that just nifty?
>
>
> This is also called "named parameters" in some languages (since parameters
> are resolved by name, not by position). And, yes, I like it too :)

Named parameters are problematic when overloading is thrown into the mix.


June 27, 2005
Chris Sauls wrote:

> Okay... I vaguely remember this getting mentioned, either by myself, or Matthew, or some other D-ite with some Python experience, and then getting discussed briefly, and more-or-less forgotten...  Well, recently I found myself randomly loving it again, and decided to bring it up once more.  :)
> 
> In python, suppose a define a function, let's call it 'foo', and suppose it takes three paramters, let's call them 'x', 'y', and 'z'.  Now, ordinarily one would just call it in the usual way:
> 
> # foo( someX, someY, someZ )
> 
> But suppose, for some reason -- maybe the values look better this way, maybe it suits the overall style of the coder writing the call, whatever -- someone decides they'd like to pass them in a different order, or that they'd like to be explicit about what each parameter is (I've felt this way often with the Win32 API, for example, and usually go about it using comments).  In python, you would do something like this:
> 
> # foo (
> #   x = someX ,
> #   y = someY ,
> #   z = someZ
> #   )
> 
> Now isn't that just nifty?  So... given the following D function decleration:
> 
> # void myfunc (Cartesian grid, Point rectOrigin, Size rectSize, Translation action) {
> #   // do stuff
> # }
> 
> Wouldn't it be nice to be able to do something like... this:
> 
> # myfunc(
> #   action     : Translation.Move(5, 10)       ,
> #   rectOrigin : Point(p_rect.x, p_rect.y)     ,
> #   rectSize   : Size(p_rect.w, p_rect.h)      ,
> #   grid       : g_grid                        ,
> # );
> 
> Now... isn't that descriptive?  :)  Naturally there would have to be strict rules.  Either A) make a given function call either associative or not, never both, or B) require that any non-associative parameters come first and be in proper order (which if I remember right, is what Python does).  Also it would, of course, have to be an error to pass a parameter twice.
> 
> I know I'm probably blowing smoke, but its something I'm fond of.  (The associative parameters, not the smoke.)
> 
> -- Chris Sauls


// Closest hack I can think of:

import std.stdio;

template myfunc()
{
  int x=0, y=0, z=0;

  void call( int xx = x, int yy=y, int zz = z )
  {
    writefln( "X %s, Y %s, Z %s", xx, yy, zz );
  }
}

void main( char[][] arg )
{
  with( myfunc!() )
  {
    x = 100;
    y = 200;
    z = -20;
    call();
  }
}

July 10, 2007
Walter Wrote:

> 
> "Sefan Zobel" <Sefan_member@pathlink.com> wrote in message news:d9n5i9$aad$1@digitaldaemon.com...
> > In article <d9lnrr$26q3$1@digitaldaemon.com>, Chris Sauls says...
> > > In python, you would do something like this:
> > >
> > ># foo (
> > >#   x = someX ,
> > >#   y = someY ,
> > >#   z = someZ
> > >#   )
> > >
> > >Now isn't that just nifty?
> >
> >
> > This is also called "named parameters" in some languages (since parameters
> > are resolved by name, not by position). And, yes, I like it too :)
> 
> Named parameters are problematic when overloading is thrown into the mix.
> 
> 
What is problematic? I used named parameters with Ada and I'm not aware of any problems with it.
In addition to making the code easier to read, named parameters avoid the burden of creating "dummy" functions when some parameters are optional.
I found nothing on the net telling that python's or ada's implementation of named parameters is problematic.
Can someone confirm/infirm on this point?

July 10, 2007
Greg wrote:
> Walter Wrote:
> 
>> "Sefan Zobel" <Sefan_member@pathlink.com> wrote in message
>> news:d9n5i9$aad$1@digitaldaemon.com...
>>> In article <d9lnrr$26q3$1@digitaldaemon.com>, Chris Sauls says...
>>>> In python, you would do something like this:
>>>>
>>>> # foo (
>>>> #   x = someX ,
>>>> #   y = someY ,
>>>> #   z = someZ
>>>> #   )
>>>>
>>>> Now isn't that just nifty?
>>>
>>> This is also called "named parameters" in some languages (since parameters
>>> are resolved by name, not by position). And, yes, I like it too :)
>> Named parameters are problematic when overloading is thrown into the mix.
>>
>>
> What is problematic? I used named parameters with Ada and I'm not aware of any problems with it.
> In addition to making the code easier to read, named parameters avoid the burden of creating "dummy" functions when some parameters are optional.
> I found nothing on the net telling that python's or ada's implementation of named parameters is problematic.
> Can someone confirm/infirm on this point?

I don't know about Ada, but Python doesn't have function overloading.
A given module can only have one function called 'foo'.

But I do recall reading an essay/rant somewhere talking about how sometimes just picking one way to do something makes life easier for everyone, and the handling of function overloading was mentioned.  I think it mentioned Ada's way and Python's way specifically. Unfortunately I can't seem to find it now.

--bb
July 10, 2007
Bill Baxter wrote:
> Greg wrote:
>> Walter Wrote:
>>
>>> "Sefan Zobel" <Sefan_member@pathlink.com> wrote in message
>>> news:d9n5i9$aad$1@digitaldaemon.com...
>>>> In article <d9lnrr$26q3$1@digitaldaemon.com>, Chris Sauls says...
>>>>> In python, you would do something like this:
>>>>>
>>>>> # foo (
>>>>> #   x = someX ,
>>>>> #   y = someY ,
>>>>> #   z = someZ
>>>>> #   )
>>>>>
>>>>> Now isn't that just nifty?
>>>>
>>>> This is also called "named parameters" in some languages (since parameters
>>>> are resolved by name, not by position). And, yes, I like it too :)
>>> Named parameters are problematic when overloading is thrown into the mix.
>>>
>>>
>> What is problematic? I used named parameters with Ada and I'm not aware of any problems with it.
>> In addition to making the code easier to read, named parameters avoid the burden of creating "dummy" functions when some parameters are optional.
>> I found nothing on the net telling that python's or ada's implementation of named parameters is problematic.
>> Can someone confirm/infirm on this point?
> 
> I don't know about Ada, but Python doesn't have function overloading.
> A given module can only have one function called 'foo'.

Just my $0.02 here: Lately I have been doing a lot more python programming and I've found it's named arguments to be a good substitute for overloading.  It's not perfect replacement, but it does have its advantages.  I have yet to find it 

problematic.

I can't speak for Ada though.

FWIW, ColdFusion script also offers named arguments, but it takes the all-or-nothing approach; if you name one arg, you must name all that you pass.  IMO, the python strategy (positional followed by named arguments) is much more intuitive.

But from what I can tell, named arguments are no more or less problematic than overloads mixed with default arguments. Right now, it's possible to create two or more overloads that can be called the same way, resulting in an ambiguity that is easily flagged by the compiler.  Named arguments just provide another way to make the same kind of mistake, so the developer must be no more aware than before.

void foobar(int d);
void foobar(int a=0,int b=0,int c=0,int d=0);
foobar(d=42); // which one?
foobar(69);   // which one?



> 
> But I do recall reading an essay/rant somewhere talking about how sometimes just picking one way to do something makes life easier for everyone, and the handling of function overloading was mentioned.  I think it mentioned Ada's way and Python's way specifically. Unfortunately I can't seem to find it now.
> 
> --bb


-- 
- EricAnderton at yahoo
July 10, 2007
Reply to Pragma,

> FWIW, ColdFusion script also offers named arguments, but it takes the
> all-or-nothing approach; if you name one arg, you must name all that
> you pass.  IMO, the python strategy (positional followed by named
> arguments) is much more intuitive.
> 

if we get named parameters, then we should also be able to get a tuple of parameter names.

maybe something like this:

is(typeof(fn) args = function);
is(fn argNames = names);

args val;
foreach(name; argNames)  val[name] = typeof(val[name]).init;



this would make my argument biding template(*) more robust.

static int fnc(int that, char has, bool lots, int[] of, float args)

// bind some args
alias Args!  (0,2,4).Become!(1,true,1e7).For!(fnc).Gives fn2;

vs.

alias Args!  (that,lots,args).Become!(1,true,1e7).For!(fnc).Gives fn2;



* http://www.dsource.org/projects/scrapple/browser/trunk/arg_bind/bind.d


July 11, 2007
Pragma wrote:
> Just my $0.02 here: Lately I have been doing a lot more python programming and I've found it's named arguments to be a good substitute for overloading.  It's not perfect replacement, but it does have its advantages.  I have yet to find it
> problematic.

I think there's not much other way you could implement overloading in a language like Python where there are no declared types.

def foo(x):
   # do one thing
def foo(y):
   # do another thing

How's the interpreter supposed to decide which one you mean?  You could overload on the number of arguments I suppose, but by doing that you'd mostly just lose the ability to unambiguously refer to functions by name (which bites us even today in D2.0  -- callback=&foo;  ... but which foo?).  Variable numbers of arguments can be reasonably implemented using defaults.

But when you do have type info that you can overload on, it's a whole different thing.

> But from what I can tell, named arguments are no more or less problematic than overloads mixed with default arguments. Right now, it's possible to create two or more overloads that can be called the same way, resulting in an ambiguity that is easily flagged by the compiler.
> Named arguments just provide another way to make the same kind of mistake, so the developer must be no more aware than before.
> 
> void foobar(int d);
> void foobar(int a=0,int b=0,int c=0,int d=0);
> foobar(d=42); // which one?
> foobar(69);   // which one?

I like the idea of named parameters too, but the contrarian's argument is that even if the compiler can catch all the errors, it still adds a lot of complexity to the language.  Especially since there are already 3 ways to overload functions (by arg types, by number of args, and with defaults).

To make it feasible I think we're first going to have to introduce a special syntax for keyword arguments.  Any D code that exists today should continue to behave the same as it does now.  Suddenly giving meaning to all parameter names would be a catastrophe.

In Lisp, for example, all keyword arguments follow a &key sigil:
   http://www.gigamonkeys.com/book/functions.html

(defun foo (bar &key (a 0) b c)
   (list bar a b c))
(foo)                   ==> ERROR missing required argument 'bar'
(foo 99)                ==> (99 0 NIL NIL)
(foo 99 :a 1)           ==> (99 1 NIL NIL)
(foo 99 :b 1)           ==> (99 0 1 NIL)

Something like that could probably be made to work for D.  I think Lisp also requires you to supply the keyword when you call it.  I.e.
(foo 3 2 1 0) doesn't work.  You have to name the keyword arguments. Even if that's not Lisp's rule, it makes sense for D, since it would cut down a lot on overload ambiguity issues.

In D you'd also be required to supply default values for all keyword args.  Be

So for D we could do something like:

void foo(int bar, :key: int a=0, int b=0, int c=0) {
   writefln("%s %s %s %s", bar,a,b,c};
}

The ":key:" token is just an example.  Could be any other unambiguous token.

--bb