[comp.lang.c++] Named arguments?

adrianb@queets.stat.washington.edu (Adrian Baddeley) (08/15/89)

In article <612@windy.dsir.govt.nz> Robert writes:
>This is to support Doug Lea's proposal for "named return values". I
>don't want to comment on the specific syntax he proposed - simply to say
>we need a better way of getting objects back from functions.

	Also, what about named arguments?

	If we ever get a C++ interpreter, we could have problems
	in calling functions with lots of arguments.
	
	Interactive statistical packages (like 'S') use
	named arguments, e.g.

		z <- scatplot(x, y, scale=3)

	Here `scatplot' could be a function that makes a scatter plot object
	from the vectors x and y; it would be sensible to have zillions
	of options, 
		scatplot(x,y,aspect,scale,xtitle,ytitle,xmargin,ymargin,etc..)
	the options need sensible defaults of course.

	Is there a better solution??

----
adrianb@castor.ms.washington.edu	(until 21 august 1989)
Adrian Baddeley, visiting Department of Statistics GN-22,
University of Washington, Seattle WA 98195, USA.
	tel (U of W): +1 206 545-2617 / 543-7237 

neal@cs.rochester.edu (Neal Gafter) (08/16/89)

In article <2179@uw-entropy.ms.washington.edu> adrianb@queets.stat.washington.edu (Adrian Baddeley) writes:

> Also, what about named arguments?

Named arguments provide a further method for overload resolution and
allow parameters other than the last ones in the argument list to be
omitted/defaulted.

I have noot seen a good syntax proposed for named arguments, so let me
make a specific proposal that is upwardly-compatible with C++, seems
natural (at least to me), and introduces no ambiguities:

extern int distance(int x, int y, int z, float scale = 1.0);

main()
{
	extern int x1, y1, z1;
	extern float scale;

	int result = distance(scale: scale1, x: x1, y: y1, z: z1);
}

Opinions?
--
Arpa:	neal@cs.rochester.edu (Neal Gafter)
UUCP:	...{rocksvax|allegra|decvax}!rochester!neal
USnail:	Department of Computer Science, U. of Rochester, N.Y. 14627
phone:	(716) 275 - 1348 (office)  or  (716) 473 - 2361 (home)

adrianb@elk.stat.washington.edu (Adrian Baddeley) (08/16/89)

In article <NEAL.89Aug15144003@jabbah.cs.rochester.edu> Neal Gafter writes:

>I have not seen a good syntax proposed for named arguments, so let me
>make a specific proposal that is upwardly-compatible with C++, seems
>natural (at least to me), and introduces no ambiguities:
>
>extern int distance(int x, int y, int z, float scale = 1.0);
>	int result = distance(scale: scale1, x: x1, y: y1, z: z1);
>
>Opinions?

	Looks good. 
	The calling syntax resembles an interpreter that I once wrote 
	for image processing. (It didn't have your nice declaration syntax.) 
		y = subset(x, margin:10)
		z = transform(x, table: y )
		print(x, copies:2, title:"Image X", pipe:"lpr -Pps")
	This seemed to satisfy users (as does 'S'). 

	'S' has a mechanism for testing in the function body
	whether a named argument was present in the function call, 
	even if it was assigned the default value. 
	Is this a good idea???

----
		
	
	
	


	
adrianb@castor.ms.washington.edu	(until 21 august 1989)
Adrian Baddeley, visiting Department of Statistics GN-22,
University of Washington, Seattle WA 98195, USA.
	tel (U of W): +1 206 545-2617 / 543-7237 

usenet@lll-winken.LLNL.GOV (Usenet news admin) (08/16/89)

In article <2179@uw-entropy.ms.washington.edu> adrianb@castor.ms.washington.edu writes:
>	Also, what about named arguments?
> [...]
>	Interactive statistical packages (like 'S') use
>	named arguments, e.g.
>
>		z <- scatplot(x, y, scale=3)
>
>	Here `scatplot' could be a function that makes a scatter plot object
>	from the vectors x and y; it would be sensible to have zillions
>	of options, 
>		scatplot(x,y,aspect,scale,xtitle,ytitle,xmargin,ymargin,etc..)
>	the options need sensible defaults of course.
>
>	Is there a better solution??
>
From: jac@muslix.llnl.gov (James Crotinger)
Path: muslix!jac

  I've often wondered why C++ default arguments have to obey this
silly rule of requiring you specify the leftmost arguments. Either
the named argument approach (ala above and...Fortran), or the approach
taken by REXX (and probably other languages) where you just use commas
to delimit the missing arguments:

        z = scatplot(x, y,, scale)

Is there a good reason that one of these isn't used?

>adrianb@castor.ms.washington.edu	(until 21 august 1989)


  Jim

zhu@csli.Stanford.EDU (Lei Zhu) (08/16/89)

In article <NEAL.89Aug15144003@jabbah.cs.rochester.edu> neal@cs.rochester.edu (Neal Gafter) writes:
>I have noot seen a good syntax proposed for named arguments, so let me
>make a specific proposal that is upwardly-compatible with C++, seems
>natural (at least to me), and introduces no ambiguities:
>
>extern int distance(int x, int y, int z, float scale = 1.0);
>
>main()
>{
>	extern int x1, y1, z1;
>	extern float scale;
>
>	int result = distance(scale: scale1, x: x1, y: y1, z: z1);
>}
>Opinions?



	That reminds me of keyword arguments in lisp, even the syntax
is similar. Your example would be like (distance :scale scale1 :x x1
:y y1 :z z1) in lisp. I find this feature to be especially useful
when there isn't a natural orderings of parameters and/or there are
lots of parameters. 

	Anyway, I think it's a good idea and your syntax is about as
good as I can of.



Just my two cents,
--Lei

wright@hsi.UUCP (Gary Wright) (08/16/89)

In article <2179@uw-entropy.ms.washington.edu> adrianb@castor.ms.washington.edu writes:

>	If we ever get a C++ interpreter, we could have problems
>	in calling functions with lots of arguments.

	Having procedures or functions with many parameters is probably
	an indication that you need to redesign your classes.
>	
>	Interactive statistical packages (like 'S') use
>	named arguments, e.g.
>
>		z <- scatplot(x, y, scale=3)
>
>	Here `scatplot' could be a function that makes a scatter plot object
>	from the vectors x and y; it would be sensible to have zillions
>	of options, 
>		scatplot(x,y,aspect,scale,xtitle,ytitle,xmargin,ymargin,etc..)
>	the options need sensible defaults of course.
>
>	Is there a better solution??

I have admittedly little experience in object oriented programming
but I have been reading quite a bit lately so I'll take a stab
at a better solution.

It seems to me that the solution is to use the OO paradigm when
designing the scatplot object.  The scatplot object should be
defined with all the necessary attributes.  When the object is created,
the attributes get appropriate default values.   The attributes
are changed by what Booch in _Software_Components_with_Ada_ calls "constructors"
(in C++ terminology, member functions that change the state of an object).

Using an Eiffel-like syntax:

	plot : SCATTER_PLOT;
	
	plot.Create;		
	-- plot object is created with possibly default values for
	-- for attributes.  For example scale would default to 1.
	
	plot.set_points(x, y);
	plot.set_scale(3);
	plot.set_xtitle("The is the title for the X axis");
	
	-- more attributes can be modified here
	
	plot.display;-- And now display the object

While some may say that this is just too verbose.  I would make the same
argument for:
	
	scatplot( xvector => x ,
		  yvector => y,
		  aspect => aspect,
		  scale => 2,
		  xtitle => "The X axis",
		  ytitle => "The Y axis",
		  ...
		  );

If you just wanted to change the scale from the default then we have:

	scatplot( xvector => x, yvector => y, scale => 3);

versus

	plot.Create;
	plot.set_points( x, y);
	plot.set_scale( 3 );

What if you want to change the scale and redisplay the object?

	plot.display;
	plot.set_scale(3);
	plot.display;

The other method does not provide a solution because all the unnamed
arguments will be set to defaults.  In other words if you use the first
method, than you are going to need seperate procedures to set
individual attributes anyway.  

I think the second method is simpler (no need to introduce named
arguments for one).  It also allows the compiler to be smart and to
inline the appropriate functions unlike the more complex constructor
which is not a good candidate for inlining.

Well, now that I have mentioned C++, Eiffel, and Ada in one article, I
should be in for some interesting mail...
-- 
Gary Wright 					...!uunet!hsi!wright
Health Systems International                    wright@hsi.com

jima@hplsla.HP.COM (Jim Adcock) (08/17/89)

Seems to me passing everything in long function parameter lists, so
long that you need to give parameters names, offer a zillion options, etc,
etc, is the antithesis of object oriented programming, and is just the 
opposite direction of where C++ programming should be going.

Instead, all those parameters and options should be represented in the
state of the underlying object, not represented a gigantic list of options
to one function.  Options are invoked by calling a method, with perhaps
a parameter or two, to turn on that option.  The option being turned on
is uniquely represented by the name of the method called -- not the name
of a named argument supplied to that option.  Defaults are established
by the constructor to an object, so that optional methods need not be
called for standard usage.

	someClass myObject;

	myObject.someOption;
	myObject.someParameter(paramvalue);
	myObject.someOption(withAParameter);

	myObject.doSomething;

As opposed to:

	doSomething(myStructure, someOption=TRUE, someParameter=paramvalue,
			someParameteredOption=withAParameter);

Long parameter list simply indicate one is still doing functional programming
rather than object oriented programming.  99.9% of object oriented programming
should be done with zero, one, or two parameters.  The simple default 
parameter capabilities built into C++ handle these cases well.  Named 
parameters would simply encourage people to continue hack functional 
programming, rather than making the mental switch to object oriented
programming.

nagle@well.UUCP (John Nagle) (08/17/89)

In article <30765@lll-winken.LLNL.GOV> jac@muslix.UUCP (James Crotinger) writes:
> ... or the approach
>taken by REXX (and probably other languages) where you just use commas
>to delimit the missing arguments:
>
>        z = scatplot(x, y,, scale)
>
>Is there a good reason that one of these isn't used?

     When a large number of optional, positional arguments are allowed,
the call can get a bit painful.

	z = plot(x,y,,,,,,1,,,'c');

is not something one finds desirable.  This sort of thing is a curse of
some mainframe job control languages.  We don't want to bring it back.

     One major advantage of named, optional arguments, is that when it
becomes necessary to add a new feature to a package, or to delete an
unused one, all the callers of the package need not be revised.  Whatever
solution is chosen should definitely retain this property.

					John Nagle

alonzo@microsoft.UUCP (Alonzo Gariepy) (08/18/89)

	Lasciate Ogne Named Arguments, Voi ch'Entrate!

In article <6590229@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
>Seems to me passing everything in long function parameter lists, so
>long that you need to give parameters names, offer a zillion options, etc,
>etc, is the antithesis of object oriented programming, and is just the 
>opposite direction of where C++ programming should be going.

Bravo!  Listen to this man and abandon your Named arguments.

Consider the smalltalk method, replaceFrom:to:with:, invoked as:  

	anIndexedCollection replaceFrom: x to: y with: aCollection.  

Who needs named arguments?  You might have another method with the name,
replaceTo:with:, where the starting index defaults to 1.  Anything more
complicated than this simple variation (reflected in the name) is unnecessary.
Since methods should generally contain no more than a dozen or two lines,
long parameter lists are probably symptomatic of design rot.

If you have to set several attributes of an object before beginning
an action, it can be done with several calls.  If the call needs two
sets of three dimensional coordinates (six parameters total) these 
are better passed as two 3D Point objects, at least if you buy much
of the object-oriented programming religion.

My preference is to do away with default arguments altogether, especially
the way they are implemented in C++ (i.e., only trailing arguments may be
omitted).

Alonzo Gariepy				// These opinions do not reflect
alonzo@microsoft			// the policy of Microsoft Corp.

arn@apple.com (Arn Schaeffer) (08/18/89)

In article <6590229@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
> Instead, all those parameters and options should be represented in the
> state of the underlying object, not represented a gigantic list of 
options
> to one function.  Options are invoked by calling a method, with perhaps
> a parameter or two, to turn on that option.  The option being turned on
> is uniquely represented by the name of the method called -- not the name
> of a named argument supplied to that option.  Defaults are established
> by the constructor to an object, so that optional methods need not be
> called for standard usage.

This could have severe implications if an object was shared by more than 
one process.  In general, it seems that ephemeral information like 
parameters should not be part of the state of the object.

Arnold Schaeffer
arn@apple.com
The opinions expressed are not necessarily those of Apple Computer.

t-robje@microsoft.UUCP (Rob Jellinghaus) (08/19/89)

In article <3671@internal.Apple.COM> arn@apple.com (Arn Schaeffer) writes:
>In article <6590229@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
>> Instead, all those parameters and options should be represented in the
>> state of the underlying object, not represented a gigantic list of 
>options
>> to one function.  Options are invoked by calling a method, with perhaps
>> a parameter or two, to turn on that option.  The option being turned on
>> is uniquely represented by the name of the method called -- not the name
>> of a named argument supplied to that option.  Defaults are established
>> by the constructor to an object, so that optional methods need not be
>> called for standard usage.
>
>This could have severe implications if an object was shared by more than 
>one process.  In general, it seems that ephemeral information like 
>parameters should not be part of the state of the object.

You're still not seeing it.  The example we've been dealing with is that
of a graph, which might have a number of different attributes (x, y axis
labels, dataset to be plotted, type of graph, etc., etc.)  In this case,
one might want to define a DATASET class, which contains the data being 
plotted.  This is the information that would be shared between processes.
Then one could define a GRAPH object, with the state information of the
particular graph to be drawn, which would contain the various parameters
of the graph, and a reference to the DATASET to be plotted.  This separates
the information that should be shared from that which need not be shared
(although if you come up with a good graph, you could simply send the 
GRAPH object to another process in order for that process to be able to
produce that graph...).

In general, any procedure with many, many parameters is probably a useful,
general-purpose, central-to-the-system routine.  Any such routine probably
encapsulates functionality that could profitably be objectified.  Even if
you balk at the idea of creating objects that seem to have no purpose
other than as argument lists, you should ocnsider the idea carefully.  It
may lead to a better object-oriented design.

>Arnold Schaeffer
>arn@apple.com
>The opinions expressed are not necessarily those of Apple Computer.

Rob Jellinghaus (robertj@CS.Yale.EDU)

adrianb@mica.stat.washington.edu (Adrian Baddeley) (08/20/89)

>In article <6590229@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
> Instead, all those parameters and options should be represented in the
> state of the underlying object, not represented a gigantic list of options
> to one function.  Options are invoked by calling a method, with perhaps
> a parameter or two, to turn on that option.  The option being turned on
> is uniquely represented by the name of the method called -- not the name
> of a named argument supplied to that option.  Defaults are established
> by the constructor to an object, so that optional methods need not be
> called for standard usage.

	OK. I'm convinced: 
		named arguments are a bad idea,
		and are a relic of functional programming.
	The only remaining issue here for *interactive* languages
	is how to call the methods with a minimum of fuss/keystrokes.

	Thanks for your advice. 

	PS: where do I join FPA (Functional Programmers Anonymous) ?

----
adrianb@castor.ms.washington.edu	(until 21 august 1989)
Adrian Baddeley, visiting Department of Statistics GN-22,
University of Washington, Seattle WA 98195, USA.
	tel (U of W): +1 206 545-2617 / 543-7237 

paulc@microsoft.UUCP (Paul Canniff 2/1011) (08/21/89)

In article <13186@well.UUCP> nagle@well.UUCP (John Nagle) writes:
> 
>      When a large number of optional, positional arguments are allowed,
> the call can get a bit painful.
> 
> 	z = plot(x,y,,,,,,1,,,'c');
> 
> is not something one finds desirable.  This sort of thing is a curse of
> some mainframe job control languages.  We don't want to bring it back.

It is, however, a simple and logical extension of the current
"optional arguments" in C++.  IMHO it is no more offensive than
the current stuff;  and if you have that many args, you have a problem
anyway -- the methods and objects are becoming too complex, and it's
time to look for component objects and methods which can be combined
to satisfy the requirement.

>      One major advantage of named, optional arguments, is that when it
> becomes necessary to add a new feature to a package, or to delete an
> unused one, all the callers of the package need not be revised.  Whatever
> solution is chosen should definitely retain this property.

Revised, no.  Recompiled, probably.  I am assuming that to retain
efficiency, the translation from a named unordered list to an unnamed
fixed list is done by the compiler, and not at runtime.  So adding
options may or may not require recompilation.

Using methods to define the state of an object seems to
provide even more flexibility that named arguments, because it allows
the object to be extended w/o revising OR RECOMPILING the original
source.  And in the world of distributing processing, where
messages to objects may actually be shipped across a network, it is
very desireable to have the new object be compatible with the
methods of the old object;  it's hard to guarantee that everyone will
be running the same version!