[comp.lang.c++] Default argument values

fox@cs.cs.columbia.edu (David Fox) (07/24/89)

It seems to me that as long as you are going to have default
argument values, you might as well allow any combination of
arguments to be omitted.  I often find myself trying to 
figure out what order to put the arguments of a function in
so that I can give the "right ones" default values.  I often
fail to find that order: many functions just aren't that
"linear".

The way to do this is to allow caller to name the parameters
the way Ada does:  foo(parm1 = a, parm3 = b, parm2 = c).
Is it too late to add this, or something like it, to C++?  G++?
Would it be a Good Thing?  Would it break anything?  Has it already
been discussed?  Can I have it by Tuesday?

David Fox
fox@cs.columbia.edu

P.S.	If it can't be part of the language, perhaps this could be
	done with a preprocessor?

beshers@cs.cs.columbia.edu (Clifford Beshers) (07/24/89)

In article <FOX.89Jul23151217@cs.cs.columbia.edu> fox@cs.cs.columbia.edu (David Fox) writes:

   It seems to me that as long as you are going to have default
   argument values, you might as well allow any combination of
   arguments to be omitted.  I often find myself trying to 
   figure out what order to put the arguments of a function in
   so that I can give the "right ones" default values.  I often
   fail to find that order: many functions just aren't that
   "linear".

I have fought this problem as well.

   The way to do this is to allow caller to name the parameters
   the way Ada does:  foo(parm1 = a, parm3 = b, parm2 = c).
   Is it too late to add this, or something like it, to C++?  G++?

The problem is that it is already there, but with different semantics:

	void foo(int parm1, int parm3, int parm2)
	{ ... }

	...

	int parm1, parm2, parm3;

	foo(parm1 = 1, parm2 = 3, parm3 = 2);

What interpretation do you place on this?
--
-----------------------------------------------
Cliff Beshers
Columbia University Computer Science Department
beshers@cs.columbia.edu

fox@cs.cs.columbia.edu (David Fox) (07/24/89)

Well, you'd need some new syntax, like

	foo(parm1 <- val1, parm3 <- val2, parm2 <- val3)
or
	foo(parm1 := val1, parm3 := val2, parm2 := val3)
or
	foo(parm1 ---> val1, parm3 ---> val2, parm2 ---> val3).

I know, some of these can be interpreted differently.
Maybe we could use some character with its eighth bit
set that shows up as a little left arrow on an IBM PC.  (1/4 a smile)
We clearly need some more symbols on our keyboards.

David Fox
fox@cs.columbia.edu

beshers@cs.cs.columbia.edu (Clifford Beshers) (07/24/89)

In article <FOX.89Jul23165225@cs.cs.columbia.edu> fox@cs.cs.columbia.edu (David Fox) writes:


   Well, you'd need some new syntax, like

	   foo(parm1 <- val1, parm3 <- val2, parm2 <- val3)
   or
	   foo(parm1 := val1, parm3 := val2, parm2 := val3)
   or
	   foo(parm1 ---> val1, parm3 ---> val2, parm2 ---> val3).

And some more semantics.  Should you allow mixing of the two
types or specification, e.g.

	foo(val1, parm3 <- val2, parm2 <- val3)

what happens with:

	foo(parm3 <- val2, val1, parm2 <- val3)

It is not a simple addition to the language, but it would be useful.
--
-----------------------------------------------
Cliff Beshers
Columbia University Computer Science Department
beshers@cs.columbia.edu

grunwald@flute.cs.uiuc.edu (Dirk Grunwald) (07/24/89)

In article <BESHERS.89Jul23152110@cs.cs.columbia.edu> beshers@cs.cs.columbia.edu (Clifford Beshers) writes:
	.....

	   void foo(int parm1, int parm3, int parm2)
	   { ... }

	   ...

	   int parm1, parm2, parm3;

	   foo(parm1 = 1, parm2 = 3, parm3 = 2);

   What interpretation do you place on this?

you don't - you switch notation:

	   foo(parm1 <- 1, parm2 <- 3, parm3 <- 2);
--
Dirk Grunwald -- Univ. of Illinois 		  (grunwald@flute.cs.uiuc.edu)

dlw@odi.com (Dan Weinreb) (07/24/89)

In article <FOX.89Jul23151217@cs.cs.columbia.edu> fox@cs.cs.columbia.edu (David Fox) writes:

   The way to do this is to allow caller to name the parameters

We did exactly this to Common Lisp, for exactly the reason you cite.
(Actually we did it to Common Lisp's ancestor, the MIT Lisp Machine
dialect of Lisp, and the feature was carried over into Common Lisp).
It turned out to be useful and is used fairly often in large Lisp
programs.  In my opinion, in the abstract, it would be a good thing.

I can certainly see why making such a change to C++ at this point in
its life might be significantly more difficult than making such a
change to Lisp was in the late 1970's.  But in this I should defer to
the C++ designers, since I don't know all the considerations and
ramifications.

Dan Weinreb		Object Design, Inc.

lpringle@bbn.com (Lewis G. Pringle) (07/25/89)

In article <FOX.89Jul23151217@cs.cs.columbia.edu> fox@cs.cs.columbia.edu (David Fox) writes:
>The way to do this is to allow caller to name the parameters
>the way Ada does:  foo(parm1 = a, parm3 = b, parm2 = c).

I second the emotion, but it may be harder than it looks.  What your are
describing (I think) are called keyword parameters.  The difficulty,
is that they impose even more ambiguity into the language.  Default params,
together with overloading, and conversion operators, already add
lots ambiguity - keyword paramers would make things even worse.

The ambiguity can - of cousrse be resolved by disambiguating rules.  Any
ADA people want to share their experiences.

						Lewis.
"OS/2: half an operating system for half a computer."

In Real Life:		Lewis Gordon Pringle Jr.
Electronic Mail:	lpringle@labs-n.bbn.com
Phone:			(617) 873-4433

schmidt@glacier.ics.uci.edu (Doug Schmidt) (07/26/89)

In article <43253@bbn.COM>, lpringle@bbn (Lewis G. Pringle) writes:
>In article <FOX.89Jul23151217@cs.cs.columbia.edu> fox@cs.cs.columbia.edu (David Fox) writes:
>>The way to do this is to allow caller to name the parameters
>>the way Ada does:  foo(parm1 = a, parm3 = b, parm2 = c).
>
>I second the emotion, but it may be harder than it looks.  What your are
>describing (I think) are called keyword parameters.  The difficulty,
>is that they impose even more ambiguity into the language.  Default params,
>together with overloading, and conversion operators, already add
>lots ambiguity - keyword paramers would make things even worse.

There's also another problem.  Allowing ``named parameters,'' a la
Ada, weakens information hiding, since formal parameter names are now
visible *outside* their original scope!

For example, consider the effect of changing a formal parameter name
in C or C++.  All you need to modify are the uses of this formal
parameter name *inside* the enclosing function.  This change is
trivial to perform using an interactive query-replace editor feature.

On the other hand, in a language that allows named parameters you need
to hunt down all instances of the formal parameter names occurring in
all *calls* to the function.  These calls are potentially spread
throughout many source files, and it becomes difficult to change the
names in an automated fashion, for the reasons alluded to above.

IMHO, named parameters are another Ada (mis)feature that adds
gratuitous complexity to the compiler and programmer without providing
much value-added benefit.

Doug
--
Master Swordsman speak of humility;             | schmidt@ics.uci.edu (ARPA)
Philosophers speak of truth;                    | office: (714) 856-4034
Saints and wisemen speak of the Tao of no doubt;
The moon, sun, and sea speaks for itself. -- Hiroshi Hamada

chase@Ozona.orc.olivetti.com (David Chase) (07/26/89)

In article <20077@paris.ics.uci.edu> schmidt@glacier.ics.uci.edu (Doug Schmidt) writes:
>There's also another problem.  Allowing ``named parameters,'' a la
>Ada, weakens information hiding, since formal parameter names are now
>visible *outside* their original scope!
>
>On the other hand, in a language that allows named parameters you need
>to hunt down all instances of the formal parameter names occurring in
>all *calls* to the function.  These calls are potentially spread
>throughout many source files, and it becomes difficult to change the
>names in an automated fashion, for the reasons alluded to above.
>
>IMHO, named parameters are another Ada (mis)feature that adds
>gratuitous complexity to the compiler and programmer without providing
>much value-added benefit.

Don't knock them until you've tried them (and compiled them).
Keyword and default parameters are in Mesa and in Modula-3 (among others),
and they work just fine.

If you have a language with separate interfaces and implementations,
the "exposes formal parameter names" argument is bogus.  From the
point of view of the called procedure, the only important thing is the
parameter position and the parameter type (yes, it is correct that the
compiler fills in the parameters at call sites if they aren't
supplied).  Thus, the names in the interface and the names in the
implementation need not correspond to each other (though I'm not sure
what Ada, Modula-3, and Mesa do about this), so nothing has been
revealed about the implementation.  That is, there's two scopes, not
one, and the conditions on signature matching say nothing about the
names of the parameters.

This is a curious sort of "information hiding"; I thought one was
supposed to hide the internals of a module, not its interface.  Choice
of parameter names has plenty to do with the interface, and very
little to do with the implementation.

Generally (anyhow), interfaces are expected to be somewhat unchanging,
and signatures of procedures are certainly expected to be somewhat
unchanging.  Even so, if you did find it necessary to change a
procedure signature, you may rest assured that the compiler will
inform you of any calls which do not conform to the standard.  If you
fail to recompile a module, then the pre-linker will inform you of
this (since generation of makefiles and dependency checking is
automated, this should not happen, anyway).

(The above may sound like some weird fairy-tale, but it's all in
place, and it all works well for Modula-3.  I don't know enough about
C++ to think of any reasons why it shouldn't be possible for C++.)

How does this differ from the exchange of two parameters in a list,
anyway?  You'd need to hunt *those* down, and (if they were of the
same type) the compiler and linker wouldn't tell you anything.  This
doesn't look like a win to me.  Keyword parameters take care of *that*
automatically.

David

jbw@eyebeam.UUCP (Jeremy B. Wohlblatt) (07/26/89)

schmidt@glacier.ics.uci.edu (Doug Schmidt) writes:
>In article <43253@bbn.COM>, lpringle@bbn (Lewis G. Pringle) writes:
>>In article <FOX.89Jul23151217@cs.cs.columbia.edu> fox@cs.cs.columbia.edu (David Fox) writes:
[talk about named parameters]

>There's also another problem.  Allowing ``named parameters,'' a la
>Ada, weakens information hiding, since formal parameter names are now
>visible *outside* their original scope!

from a software engineering point of view, i see no problem here.  the
keyword names need only be visible in the function call, which is the
interface between the calling routine and the function itself.  why
shouldn't some aspects of both be visible there?

already, the calling routine must know the order and types of the arguments (to say
nothing of the semantics), so why not provide a name if it helps the caller
write the call more clearly?  e.g., in a language which gives you defaults
and named paramenter, you might want to use an 8-parameter function but with
all defaults except one.  you could write this simply as

	load_file(infile <- foo);

rather than copying all the defaults or writing something like

	load_file(,,,, foo,,,);

basically this frees you from having to know the order of arguments
at the expense of requiring you to know the names of the ones you're
interested in.  this may make the call more clear.

consider

	copy (x, y);

versus

	copy (from <- y, to <- x);

note that i did not use the traditional `=' for parameter assignment.
it seems too hard to read and understand function calls when ordinary
assignment and parameter assignment use the same syntax, e.g.

	{
		int y;
		...
		foo (x = 3); // keyword assignment
		foo (y = 3); // local variable assignment
	}

>For example, consider the effect of changing a formal parameter name
>in C or C++.  All you need to modify are the uses of this formal
>parameter name *inside* the enclosing function.  This change is
>trivial to perform using an interactive query-replace editor feature.

but this is a problem with editors, not the software engineering structure
of the program.  the solution is better multi-file editors.  moreover,
if you change the *order* of the arguments, you've got the same problem
anyway, right?  it's reasonable to visit all the function calls whenever
you change the interface to the function.

>On the other hand, in a language that allows named parameters you need
>to hunt down all instances of the formal parameter names occurring in
>all *calls* to the function.  These calls are potentially spread
>throughout many source files, and it becomes difficult to change the
>names in an automated fashion, for the reasons alluded to above.

on the other hand, you can change the order of the arguments and *not*
have to visit all the calls if they always used the keyword names!

>IMHO, named parameters are another Ada (mis)feature that adds
>gratuitous complexity to the compiler and programmer without providing
>much value-added benefit.

i may agree with you that this isn't a tremendously exciting feature,
but not for the reasons you cite.  personally, though, it seems to me
that if the language has a clear syntax associated with named parameters
(like the `<-' i suggested above) then there's little room for ambiguity.
nor should the compiler be all that more complex.

					-- jeremy
these opinions might not be those of my employer.  they might not even be mine.
jeremy b. wohlblatt: samsung software america, inc.
	uucp: {decvax!{gsg,cg-atla},uunet,ulowell}!ginosko!jbw
	internet:	jbw@ginosko.samsung.com

dlw@odi.com (Dan Weinreb) (07/26/89)

In article <20077@paris.ics.uci.edu> schmidt@glacier.ics.uci.edu (Doug Schmidt) writes:

   There's also another problem.  Allowing ``named parameters,'' a la
   Ada, weakens information hiding, since formal parameter names are now
   visible *outside* their original scope!

You can allow the formal parameter name to be different from the
outside-visible keyword name.  Common Lisp allows this.  They're the
same by default but you can control it if you want to.  People
interested in this sort of language feature might want to check out
Common Lisp, which has had it for a long time.  However, I'm not sure
there's much point to discussing it on comp.lang.c++.  I like the idea
too, but based on the philosophy of C++ evolution that I've heard, as
I understand it, this is not the sort of change we're likely to see in
C++.

alonzo@microsoft.UUCP (Alonzo Gariepy) (07/26/89)

>In article <FOX.89Jul23165225@cs.cs.columbia.edu> fox@cs.cs.columbia.edu (David Fox) writes:
>
>
>   Well, you'd need some new syntax, like
>
>	   foo(parm1 <- val1, parm3 <- val2, parm2 <- val3)

Why not some more simple compromise such as allowing empty commas.
This way, all the default parameters don't have to be at the end
of the list.

int foo(a = 3, b, c = 12, d = 12);

	foo(4, 7, , 10);     // c gets 12
	foo(, 6);            // a gets 3, c gets 12, d gets 12
        foo(4,,7);           // **error**  b has no default

Or am I naive?

Alonzo Gariepy                                   // If Microsoft has an opinion,
alonzo@microsoft                                 // they haven't told it to me.

benson@odi.com (Benson I. Margulies) (07/26/89)

In article <20077@paris.ics.uci.edu> schmidt@glacier.ics.uci.edu (Doug Schmidt) writes:
>In article <43253@bbn.COM>, lpringle@bbn (Lewis G. Pringle) writes:
>>In article <FOX.89Jul23151217@cs.cs.columbia.edu> fox@cs.cs.columbia.edu (David Fox) writes:
>>>The way to do this is to allow caller to name the parameters
>>>the way Ada does:  foo(parm1 = a, parm3 = b, parm2 = c).
>>
>>I second the emotion, but it may be harder than it looks.  What your are
>>describing (I think) are called keyword parameters.  The difficulty,
>>is that they impose even more ambiguity into the language.  Default params,
>>together with overloading, and conversion operators, already add
>>lots ambiguity - keyword paramers would make things even worse.
>
>There's also another problem.  Allowing ``named parameters,'' a la
>Ada, weakens information hiding, since formal parameter names are now
>visible *outside* their original scope!
>

Not true. In Common Lisp, it is possible to decouple the two.

(defun foo (&key (:x 1 y)) 
	(+ y 1))

means:

- call it like

(foo :x VAL)

- bind a variable named "y" in the body.

- Default to 1.

C++ need "merely" design a parallel syntax.

>IMHO, named parameters are another Ada (mis)feature that adds
>gratuitous complexity to the compiler and programmer without providing
>much value-added benefit.

If the language didn't have optional params with defaults, I would be
sympathetic to adding neither those nor by-name parameters.  However,
as it is, functions tend to become incomprehensible as they are
overloaded. Constructors are particularly subject to this abuse.  One
sees (even in the documentation from AT&T) substantially different
behavior triggered by subtlties of the argument list.

I believe that the problem results from a particular limitation.
Often, I desire a family of functions with nearly identical content
but different parameters. I can write them in C++ as a bunch of inline
wrappers and one body function, but inlines don't always work, and I
begrudge the procedure call.

In PL/I, this was addressed by multiple entrypoints. A standard
Multics PL/I cliche was:

procedure full_interface (x, y, z, q, r, s);


...

goto start;

entry quick_interface (x, y, z);

q = qdefault;
r = rdefault;
s = sdefault;

start:


end;

Optional parameters attempt to address this case. However, they lose
the self-documentation of the different entry names. Constructors are
particularly plagued by this. 

The experience in the lisp community was that optional arguments are
often the route to disaster. Who can remember how many zeros to supply
to get out to the critical argument I need today? If you are lucky,
the optionals will have types without inter-conversions, and then
errors will be obvious. But if there are 4 optionals in a row that are
either numbers or pointers, then you can have one too many or one too
few and never find out till the bridge falls down. In a word,
"unsafe".

What might a syntax be in C++? Its not obvious. A keyword seems to be
needed.

int x (byname (name1, default1, var1), (name2, default2, var2)) {

If "var" is omitted, then name is the name.  If default and var are
omitted, then the parens can be omitted.

How would one call it? That's the ugly part, I fear.

x (name1:=val1, name2:=val2)

would serve. 



Benson I. Margulies

lindsay@MATHOM.GANDALF.CS.CMU.EDU (Donald Lindsay) (07/27/89)

In article <20077@paris.ics.uci.edu> schmidt@glacier.ics.uci.edu (Doug Schmidt) writes:
>IMHO, named parameters are another Ada (mis)feature that adds
>gratuitous complexity to the compiler and programmer without providing
>much value-added benefit.

Well, yes. They allowed the intermixture of positional and named
arguments, this making it potentially hard to understand the
positional material.

If you really need named arguments, you can have them now, even in C
and Pascal. Pass a data structure, and precede the call with
assignments to named fields. It doesn't allow a simple defaulting
scheme, but there are a variety of less-simple schemes that can be
pressed into service. And, it has wins of its own, such as using
const structures, or ones that don't vary around a loop.
-- 
Don		D.C.Lindsay 	Carnegie Mellon School of Computer Science

minshall@kinetics.UUCP (Greg Minshall) (08/02/89)

I assume that various participants in this newsgroup had occasion in years
past to use the IBM 370 assembler macro facility.  How much this discussion
of named parameters (and even default parameter values in C++) remind/amuses
me of the above assembler.

The macro facility allowed both "positional" and "keyword" parameters.
Positional parameters needed to come first in the parameter list; any
or all could be left out (an intervening positionaly parameter could
be excluded by use of the "comma" operator: foo a,b,,d).  Keyword parameters
could be specified (in the call) in any order; they could be defined by
the macro to have default values.

It was quite an assembler.

Greg Minshall			Kinetics/Excelan/Novell
minshall@kinetics.com		1-415-947-0998