Topic: Idea for self documenting parameter passing


Author: allan_w@my-dejanews.com (Allan W)
Date: Tue, 25 Feb 2003 22:00:02 +0000 (UTC)
Raw View
hyrosen@mail.com (Hyman Rosen) wrote
> Allan W wrote:
> > Hyman Rosen gets closer by suggesting that we borrow some syntax from
> > the initializer lists in constructors. But this too can lead to
> > ambiguity:
> >     f(a(1), b(a));
>
> Umm, that's *not* what I said. Please reread my post.

I meant no offense. I was trying to summarize the various ideas presented
so far (at least in this thread). Apparently I was not 100% accurate. I
sincerely apologize.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hyrosen@mail.com (Hyman Rosen)
Date: Mon, 17 Feb 2003 17:09:22 +0000 (UTC)
Raw View
Allan W wrote:
> Hyman Rosen gets closer by suggesting that we borrow some syntax from
> the initializer lists in constructors. But this too can lead to
> ambiguity:
>     f(a(1), b(a));

Umm, that's *not* what I said. Please reread my post.
I just said that there is precedent in C++ for having
the same name mean two different things in a construct,
namely in 'struct X { int a; X(int a) : a(a) { } };',
'a(a)' means initialize field 'a' with parameter 'a'.

> I don't know if David Abrahams suggested the colen notation, or if
> he was merely defending it. I like this the best so far.
>     f(a:1, b:a);

Yes, this seems best to me as well. And this would be fine:
     f(a:a, b:a);

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: allan_w@my-dejanews.com (Allan W)
Date: Thu, 13 Feb 2003 21:06:37 +0000 (UTC)
Raw View
dave@boost-consulting.com ("Dave Abrahams") wrote

> I'm not proposing to solve it for named parameters in a way that allows the
> analogue of #2, i.e.:
>
>    void f(int a, int b);
>
>     ...
>
>    // no "a" in scope
>    f(a = 1, b = a);
                  ^ If there's no "a" in scope, what is this?

> but if we wanted to allow that, I guess there's precedent for it in the
> standard somewhere.

I hope not. I shudder to think of the consequences.

The arguments to a function call are expressions. Assignment is legal
in expressions. In short,
    f(a=1, b=a);
already has a meaning that would silently change.

(It also happens to be illegal, because a is both used and changed
without an intervening sequence point, but that's irrelevant to the
topic at hand.)

Hyman Rosen gets closer by suggesting that we borrow some syntax from
the initializer lists in constructors. But this too can lead to
ambiguity:
    f(a(1), b(a));
Are we calling f, using named parameters a and b? Or are we using
positional notation, and calling functions a() and b()?

I don't know if David Abrahams suggested the colen notation, or if
he was merely defending it. I like this the best so far.
    f(a:1, b:a);
Namespace and/or class specifiers always use double-colen, not
single colen. But we do have single colens in the trinary operator,
so I'm worried that it still might be ambiguous. I've tried without
success to come up with a legal expression that would be broken
with this idea.
    f(a?b:c, d?e:f);
clearly uses positional notation, while
    f(a:a?b:c, b:d?e:f);
clearly uses named parameters. With named parameters, the name and
colen always come at the beginning (before any possible question mark);
perhaps this avoids any problem.

If people balk at the idea of using a colen here, we could always
go for the := syntax.
    f(a:=a?b:c, b:=d?e:f);
but I like the single colen better. Obviously C++ can't concern itself
much with details of other languages, but currently people that switch
between language have a tendency to use = for both assignment and
comparison. Using := for something other than assignment would only
make this worse.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dave@boost-consulting.com ("Dave Abrahams")
Date: Thu, 6 Feb 2003 01:35:25 +0000 (UTC)
Raw View
In news:1044476360.346881@master.nyc.kbcfp.com,
Hyman Rosen <hyrosen@mail.com> typed:

> In fact, C++ already has this, in constructors:
>
> struct A { int a, b; A(int a, int b) : a(a), b(b) { } };
>
> In 'a(a)', the left 'a' is the member name and the right 'a'
> is the parameter name.

Nice herring-painting insight!

As a matter of fact, C++ solves this problem somehow:

  // legal
  struct X
  {
     X(int a) : a(a), b(a) {} // #1
     X() : a(1), b(a) {}      // #2
     int a,b;
  };

I'm not proposing to solve it for named parameters in a way that allows the
analogue of #2, i.e.:

   void f(int a, int b);

    ...

   // no "a" in scope
   f(a = 1, b = a);

but if we wanted to allow that, I guess there's precedent for it in the
standard somewhere.

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: pkl@mailme.dk ("Peter Koch Larsen")
Date: Wed, 5 Feb 2003 14:54:31 +0000 (UTC)
Raw View
"Allan W" <allan_w@my-dejanews.com> skrev i en meddelelse
news:7f2735a5.0302031703.59dc0360@posting.google.com...
> stephen.clamage@sun.com (Stephen Clamage) wrote
[snip]
> > Something().height(20).width(30).depth(10)();
> >
> > The last line to my eye is no less readable than various proposals for
> > naming arguments in function calls. Add overloaded constructors or
> > default parameters to Something to create default values.
>
> As I've done above with 0's.
>
> Well, there certainly is SOME run-time penalty. The three member
> variables defaulted to one value, and then got overridden with
> another. True, in the case of int types it would be difficult to
> measure the run-time penalty, but it certainly does exist.

Hi Allan

Regarding runtime penalties, even not so good optimizing compilers should be
able to eliminate that overhead. For an example, please see my posts in
another thread here in std.c++:  proposal using default parameters.

Kind regards
Peter



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dave@boost-consulting.com ("Dave Abrahams")
Date: Wed, 5 Feb 2003 19:36:55 +0000 (UTC)
Raw View
In news:cuyWtWGXhjO+EwgR@robinton.demon.co.uk,
Francis Glassborow <francis.glassborow@ntlworld.com> typed:
> In article <uu1fp515k.fsf@boost-consulting.com>, David Abrahams
> <dave@boost-consulting.com> writes
> > I'm sorry, I can't picture what you mean, and I have an even harder
> > time connecting it to the idea of namespace leakage.  Could you show
> > an example of where the proposal makes the position of a name in a
> > definition cause a change in meaning, and can you make a connection
> > with the assertion I'm challenging?
>
<snip context>

> If this were going to be done in C and/or C++, a better or at least
> more likely syntax would be either that of C99's designated
> initializers or the C++ initializer list.
>
> That is given the prototype:
>
>         int func(int i1, int i2, int i3);
>
> The C99 style call would be:
>
>         func(.i2=3, .i1=5, .i3=9);
>
> ....and the C++ initializer list style would be:
>
>     func( i2 : 3, i3 : 9, i1 : 5);
>
> The very big problem with this is that the identifiers for formal
> arguments in function prototypes are completely optional and only have
> prototype scope in any case.  On top of that, you can have multiple
> prototypes in scope with different names for the same arguments.
>
> Now given func in the above and a usage context in which i1, i2, and i3
> are in scope consider (other than as formal parameter names):
>
> func(i2 : i1, i3 : i2, i1 : i3);
>
> What is meant by each of the names?

It's confusing textually, but simple logically: a name to the left of a
colon refers to a parameter position, while a name to the right of a colon
refers to a value that's in scope.  So the call is equivalent to:

    func(i3, i1, i2)

It's easy enough to construct a textually confusing example like this, but I
think it's **extremely** unlikely to arise in practice.  Much more likely
would be:

    func(i1:i1, i2:i2, i3:i3)

> Now consider the same code if only i1 has been declared. Do the uses of
> i2 and i3 refer to the formal parameters with those names?


No, it would be ill-formed, otherwise the rules would be too confusing.

It all works out well enough provided you pick reasonable rules ;-)

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hyrosen@mail.com (Hyman Rosen)
Date: Wed, 5 Feb 2003 20:21:58 +0000 (UTC)
Raw View
Dave Abrahams wrote:
>>Now given func in the above and a usage context in which i1, i2, and i3
>>are in scope consider (other than as formal parameter names):
>>
>>func(i2 : i1, i3 : i2, i1 : i3);
>>
>>What is meant by each of the names?
>
> It's confusing textually, but simple logically: a name to the left of a
> colon refers to a parameter position, while a name to the right of a colon
> refers to a value that's in scope.

In fact, C++ already has this, in constructors:

struct A { int a, b; A(int a, int b) : a(a), b(b) { } };

In 'a(a)', the left 'a' is the member name and the right 'a'
is the parameter name.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Fri, 31 Jan 2003 06:09:21 +0000 (UTC)
Raw View
francis.glassborow@ntlworld.com (Francis Glassborow) writes:

> In article <u4r7rcukj.fsf@boost-consulting.com>, David
> Abrahams <dave@boost-consulting.com> writes
>>> No, there are plenty of other ways to deal with that
>>> problem, it is the wider problem of leaking parameter
>>> names into the containing namespace that is, IMO, a
>>> killer.
>>>
>>
>>I have some serious problems with the assertion you seem to be making
>>that the proposal would cause parameter names to "leak out into the
>>containing namespace".  The proposed syntaxes all clearly delineate
>>these identifiers from names which refer to entities in the caller's
>>namespace, so it seems to me that there's absolutely no reason for us
>>to choose a specification which causes them to leak in any meaningful
>>way.  Can you justify or qualify your claim somehow?
>
> I can think of no other context in which we allow the
> position of a name in a definition to give it different
> meanings.

I'm sorry, I can't picture what you mean, and I have an even harder
time connecting it to the idea of namespace leakage.  Could you show
an example of where the proposal makes the position of a name in a
definition cause a change in meaning, and can you make a connection
with the assertion I'm challenging?

Thanks for your patience,
Dave

--
                       David Abrahams
   dave@boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: pierrebai@hotmail.com (Pierre Baillargeon)
Date: Sat, 1 Feb 2003 00:30:01 +0000 (UTC)
Raw View
jackklein@spamcop.net (Jack Klein) wrote in message news:<ttre3v094brkgnibfh6pvhillrq230ijt2@4ax.com>...
>
> You could say that position independent argument passing would be
> restricted to functions whose prototypes supplied names, but what if
> you have multiple prototypes with different names?  Consider:

...

> Frankly, unless you are prepared to require and enforce a "one
> prototype" rule, insisting that all prototypes of a function anywhere
> in a program, including its definition, must use exactly the same
> names, I don't see how this would be practical.  And I think a "one
> prototype" rule would break too much existing code to be seriously
> considered for addition to the standard.

Then simply specify that any function without parameter names or with
inconsistent names in a translation unit cannot be used with
named-parameter calling syntax. Breaks no code. And probably works
with most code since redeclaring function prototypes is rare, except
in the actual definition of the function. After all the corrolary for
"don't pay for what you don't use" is "pay for what you want to
use..."

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: fma@doe.carleton.ca (f)
Date: Sat, 1 Feb 2003 00:34:27 +0000 (UTC)
Raw View
danielgutson@hotmail.com (danielgutson@hotmail.com) wrote in message news:<23478c42.0301292201.7e728bef@posting.google.com>...
> But, the only complain I have against having **only** this mechanism
> (and no parameter defaulting as in my proposal using 'default'
> keyword) is that, sometimes remembering the parameter name is as
> useless as remembering its position in other situation.
> For example: let's consider the 'inc' function:
>
>    void inc(int& x)
>    {  x++; }
>
> who would ever care the name given to its parameter?
>
> This is just an example, and not full applicable since there are no
> default parameters (in fact, only one). But the same situation can
> even exist with them.
> Perhaps another example: drawing a circle:
>
> void drawCircle( int radious = 1, int centerX = 0, int centerY = 0,
> Color color = green);
>
> Coming from previous libraries, one could be customed with the order;
> the name is a matter of the implementer (radious ~ r ~ delta ~ ...;
> color ~ colour ~ c; centerX ~ x0 ~ x; centerY ~ y0 ~ y);
>
> So <sometimes> ordering is more important (or mnemonic) than names.
>
> AGAIN: I'm not against this proposal; just saying that should be
> complementary with the other (defaulting params). (complementary, but
> mutual exclusive during function call).
>
> In fact, if named parameters is implemented, then I think the function
> programmer should be able to disable this feature (for example reusing
> the 'explicit' keyword).
>
>  Daniel.

The way it works in Verilog is that you can use
either positional or exlicit parameter association
for each function call (or rather, component
instantiation in the case of Verilog).  You just
can't mix them in the same function call.

About positional association being better for those
familiar with library routines, the argument can
be made that any re-usable parcel of code becomes
familiar with great use.  But not everyone uses
all parcels alot.  So self-documentation through
explicit association really helps.  The person
who wrote the code isn't necessarilyt the same
as the person who has to read it.  Even so, the
way it works in Verilog is that the code writer
can still choose not to use explicit association.

I don't pretend that all difficulties with
incorporating explicit association (or named
arguments) is resolved by the above two paragraphs.
It's just to address the points you raise.  I'm
still reading some of the previous responses...

Fred

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: francis.glassborow@ntlworld.com (Francis Glassborow)
Date: Sat, 1 Feb 2003 00:35:58 +0000 (UTC)
Raw View
In article <uu1fp515k.fsf@boost-consulting.com>, David Abrahams
<dave@boost-consulting.com> writes
>I'm sorry, I can't picture what you mean, and I have an even harder
>time connecting it to the idea of namespace leakage.  Could you show
>an example of where the proposal makes the position of a name in a
>definition cause a change in meaning, and can you make a connection
>with the assertion I'm challenging?

Context:

> I've got a beef about how parameters are passed in
> C/C++.  The function's formal arguments are bound
> to the informal arguments (for lack of a better word?)
> supplied by the caller of the function.  The association
> is made by the position of the arguments.  This has
> always bugged me a bit because I recall fortran days,
> where argument list would sprawl over many lines.  It
> was easy to have misaslignment in positional
> association.

        [snip]

>      Module_Definition_Name    Instance_1 (
>          .Formal_Param_1 ( Informal_Param_1 ) ,
>          .Formal_Param_2 ( Informal_Param_2 ) ,
>              :
>              :
>          .Formal_Param_N ( Informal_Param_N )
>      ) ;

If this were going to be done in C and/or C++, a better or at least
more likely syntax would be either that of C99's designated
initializers or the C++ initializer list.

That is given the prototype:

        int func(int i1, int i2, int i3);

The C99 style call would be:

        func(.i2=3, .i1=5, .i3=9);

....and the C++ initializer list style would be:

    func( i2 : 3, i3 : 9, i1 : 5);

The very big problem with this is that the identifiers for formal
arguments in function prototypes are completely optional and only have
prototype scope in any case.  On top of that, you can have multiple
prototypes in scope with different names for the same arguments.

Now given func in the above and a usage context in which i1, i2, and i3
are in scope consider (other than as formal parameter names):

func(i2 : i1, i3 : i2, i1 : i3);

What is meant by each of the names?

Now consider the same code if only i1 has been declared. Do the uses of
i2 and i3 refer to the formal parameters with those names?



--
ACCU Spring Conference 2003 April 2-5
The Conference you cannot afford to miss
Check the details: http://www.accuconference.co.uk/
Francis Glassborow      ACCU

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: stephen.clamage@sun.com (Stephen Clamage)
Date: Sat, 1 Feb 2003 16:12:34 +0000 (UTC)
Raw View
On Thu, 30 Jan 2003 16:20:26 +0000 (UTC),
francis.glassborow@ntlworld.com (Francis Glassborow) wrote:

>In article <3E384FCF.E908FDE1@doe.carleton.ca>, Shing-Fat Fred Ma
><fma@doe.carleton.ca> writes
>>This is alot more complicated than
>>I initially thought.  With backward
>>compatibility being a major issue,
>>and the fact that the prototypes and
>>source code can be separate.  I
>>think that resolving any conflicts
>>with further overloading may cause
>>more confusion, which would be
>>self defeating.  It works for verilog
>>because the protocol was defined
>>from the beginning.  Anyway, thanks
>>for the listen.
>
>And likewise, thanks for listening to the responses and reacting
>sensibly to them (much in contrast to the way a proposer is reacting in
>another active thread.). It often helps to have ideas like yours put up
>for discussion exactly because it allows us to see the pros and cons. I
>think many of us have a hankering after being able to provide named
>arguments but with C++ the way it is the costs appear to be too high.

Named arguments for functions was formally proposed twice to the C++
committee, and rejected both times because of all the problems listed
in this thread, plus a few more. It interacts badly with function
overloading, and makes the parameter names in function declarations
important when previously they had no significance.

I didn't see anybody in this thread mention existing alternatives to
named function parameters. Instead of bending the language to support
an ill-conceived C API (application programming interface), use a C++
API. Don't have a long list of single parameters. Pass a struct or
class, and use constructors or other access functions to set the
values. Or use a function object instead of a function. For example:

class Something {
public:
 Something& height(int h) : height_(h) { return *this; }
 Something& width(int w) : width_(w) { return *this; }
 Something& depth(int d) : depth_(d) { return *this; }
 result_type operator()(); // does the work
private:
 int height_, width_, depth_;
};

Something().height(20).width(30).depth(10)();

The last line to my eye is no less readable than various proposals for
naming arguments in function calls. Add overloaded constructors or
default parameters to Something to create default values.

If you are stuck with an unpleasant C API -- loose functions with lots
of parameters -- wrap them in C++ classes that give you a pleasant C++
API. Using simple inline functions as above, you have no run-time
penalty.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: allan_w@my-dejanews.com (Allan W)
Date: Tue, 4 Feb 2003 06:44:26 +0000 (UTC)
Raw View
stephen.clamage@sun.com (Stephen Clamage) wrote
> I didn't see anybody in this thread mention existing alternatives to
> named function parameters. Instead of bending the language to support
> an ill-conceived C API (application programming interface), use a C++
> API. Don't have a long list of single parameters. Pass a struct or
> class, and use constructors or other access functions to set the
> values. Or use a function object instead of a function. For example:
>
> class Something {
> public:
>  Something& height(int h) : height_(h) { return *this; }
>  Something& width(int w) : width_(w) { return *this; }
>  Something& depth(int d) : depth_(d) { return *this; }
>  result_type operator()(); // does the work
> private:
>  int height_, width_, depth_;
> };

Is that legal? It looks like you're using a ctor-initializer on
functions instead of constructors.

Perhaps you menat this:
   class Something {
   public:
      Something() : height_(0), width_(0), depth_(0) {}
      Something& height(int h) { height_=h; return *this; }
      Something& width (int w) { width_ =w; return *this; }
      Something& depth (int d) { depth_ =d; return *this; }
   private:
      int height_, width_, depth_;
   };

That definition makes this next line legal, with semantics
you apparently want:

> Something().height(20).width(30).depth(10)();
>
> The last line to my eye is no less readable than various proposals for
> naming arguments in function calls. Add overloaded constructors or
> default parameters to Something to create default values.

As I've done above with 0's.

> If you are stuck with an unpleasant C API -- loose functions with lots
> of parameters -- wrap them in C++ classes that give you a pleasant C++
> API. Using simple inline functions as above, you have no run-time
> penalty.

Well, there certainly is SOME run-time penalty. The three member
variables defaulted to one value, and then got overridden with
another. True, in the case of int types it would be difficult to
measure the run-time penalty, but it certainly does exist.

Then again, maybe we could do the same thing with pointers.
    // Old C-style API
    void processEmployees(
        Employee*before,          int beforecount,
        Employee*salarychanged,   int salarycount,
        Employee*locationchanged, int locationcount,
        Employee*layoff,          int layoffchanged,
        Employee**result,         int *resultcount);

    // New-style API
    class VendProcEmployees {
    private:
        Employee*bef, *sal, *loc, *lay;
        int     cbef, csal, cloc, clay;
    public:
        VendProcEmployees() : bef(0), sal(0), loc(0), lay(0)
                             ,cbef(0), csal(0), cloc(0), clay(0) {}
        VendProcEmployees &before(Employee*b, int count)
            { bef=b; cbef=count; return *this; }
        VendProcEmployees &salary(Employee*s, int count)
            { sal=s; csal=count; return *this; }
        VendProcEmployees &location(Employee*l, int count)
            { loc=s; cloc=count; return *this; }
        VendProcEmployees &layoff(Employee*l, int count)
            { lay=s; clay=count; return *this; }
        void operator()
            { processEmployees(bef,cbef, sal,csal, loc,slac, lay,clay); }
    };

    // Usage:
    // This example changes the salaries and locations but
    // doesn't lay anyone off (or rehire any).
    VendProcEmployees()
        .before(BEmp, empcount)
        .salary(SEmp,salcount)
        .location(LLEmp, loccount)();

But this DOES default-construct four pointers and four ints, and
then immediately change three and three of them...

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: jackklein@spamcop.net (Jack Klein)
Date: Wed, 29 Jan 2003 07:39:39 +0000 (UTC)
Raw View
On Mon, 27 Jan 2003 22:55:27 +0000 (UTC), fma@doe.carleton.ca (fred)
wrote in comp.std.c++:

> Hello,
>
> Someone suggested posting my article
> here....
>
> Fred
>
> -------- Original Message --------
> Subject: Idea for self documenting parameter passing
> Date: Sun, 26 Jan 2003 22:18:15 -0500
> From: f <fma@doe.carleton.ca>
> Reply-To: fma@doe.carleton.ca
> Organization: Bell Sympatico
> Newsgroups: comp.lang.c++
>
> Hello,
>
> I've got a beef about how parameters are passed in
> C/C++.  The function's formal arguments are bound
> to the informal arguments (for lack of a better word?)
> supplied by the caller of the function.  The association
> is made by the position of the arguments.  This has
> always bugged me a bit because I recall fortran days,
> where argument list would sprawl over many lines.  It
> was easy to have misaslignment in positional
> association.

 [snip]

>      Module_Definition_Name    Instance_1 (
>          .Formal_Param_1 ( Informal_Param_1 ) ,
>          .Formal_Param_2 ( Informal_Param_2 ) ,
>              :
>              :
>          .Formal_Param_N ( Informal_Param_N )
>      ) ;

If this were going to be done in C and/or C++, a better or at least
more likely syntax would be either that of C99's designated
initializers or the C++ initializer list.

That is given the prototype:

 int func(int i1, int i2, int i3);

The C99 style call would be:

 func(.i2=3, .i1=5, .i3=9);

....and the C++ initializer list style would be:

    func( i2 : 3, i3 : 9, i1 : 5);

The very big problem with this is that the identifiers for formal
arguments in function prototypes are completely optional and only have
prototype scope in any case.  On top of that, you can have multiple
prototypes in scope with different names for the same arguments.

How do you deal with this prototype:

   int func(int, int, int);

?

You could say that position independent argument passing would be
restricted to functions whose prototypes supplied names, but what if
you have multiple prototypes with different names?  Consider:

(someheader.h)
int func(int i1, int i2, int i3);

(some source code file)

#include "someheader.h"

inf func(int x, int y, int z)
{
   // body
}

Or even worse, in that source code file:

int func(int i3, int i2, int i1)
{
   // body
}

Now assume a call to func() from somewhere in the same source file as
its definition, after that definition.  Given the first definition,
should it accept "i1" as the name for the first parameter, or "x", or
both?  Given the second definition, will "i3" set the first or third
parameter?

You could say impose a rule that, given multiple prototypes in scope,
requires that a compiler use the names from the most recently parsed
prototype.  That would make "x" valid in the first example, and "i1"
invalid.

But consider the second case again.  If a call to func() is in
some_other_source_file.cpp that includes someheader.h, i1 will refer
to the first parameter.  If that function is cut from that header and
pasted into the bottom of the file with the second definition, that
same i1 will not refer to the third parameter.

Frankly, unless you are prepared to require and enforce a "one
prototype" rule, insisting that all prototypes of a function anywhere
in a program, including its definition, must use exactly the same
names, I don't see how this would be practical.  And I think a "one
prototype" rule would break too much existing code to be seriously
considered for addition to the standard.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: francis.glassborow@ntlworld.com (Francis Glassborow)
Date: Wed, 29 Jan 2003 17:36:39 +0000 (UTC)
Raw View
In article <ttre3v094brkgnibfh6pvhillrq230ijt2@4ax.com>, Jack Klein
<jackklein@spamcop.net> writes
>If this were going to be done in C and/or C++, a better or at least
>more likely syntax would be either that of C99's designated
>initializers or the C++ initializer list.
>
>That is given the prototype:
>
>       int func(int i1, int i2, int i3);
>
>The C99 style call would be:
>
>       func(.i2=3, .i1=5, .i3=9);
>
>....and the C++ initializer list style would be:
>
>    func( i2 : 3, i3 : 9, i1 : 5);
>
>The very big problem with this is that the identifiers for formal
>arguments in function prototypes are completely optional and only have
>prototype scope in any case.  On top of that, you can have multiple
>prototypes in scope with different names for the same arguments.

The multiple names problem can be solved by ruling that such cases
should be dealt with as ambiguous, ill-formed or whatever.

But the serious problem is that we had good reasons for placing
'prototype' (quoted because there is no such term in C++, as C++ has a
single syntax for declaring function names) names in their own scope; it
prevents such names leaking out into global namespace. Proposals such as
the above would change that and impact on the single most complicated
(and, IMO, confused) aspect of C++, name look-up. That seriously worries
me.

The upshot is that pursuing such proposals would burn very large amounts
of Committee time. I think that means that proponents must demonstrate a
commensurate gain for programmers as a whole.

>
>How do you deal with this prototype:
>
>   int func(int, int, int);
>
>?
>
>You could say that position independent argument passing would be
>restricted to functions whose prototypes supplied names, but what if
>you have multiple prototypes with different names?  Consider:
>
>(someheader.h)
>int func(int i1, int i2, int i3);
>
>(some source code file)
>
>#include "someheader.h"
>
>inf func(int x, int y, int z)
>{
>   // body
>}
>
>Or even worse, in that source code file:
>
>int func(int i3, int i2, int i1)
>{
>   // body
>}
>
>Now assume a call to func() from somewhere in the same source file as
>its definition, after that definition.  Given the first definition,
>should it accept "i1" as the name for the first parameter, or "x", or
>both?  Given the second definition, will "i3" set the first or third
>parameter?
>
>You could say impose a rule that, given multiple prototypes in scope,
>requires that a compiler use the names from the most recently parsed
>prototype.  That would make "x" valid in the first example, and "i1"
>invalid.

That would be silly. Just deal with ambiguity as we do everywhere else.
But the crux of the issue is if the parameter names are also names of
other entities that are in scope.

>
>But consider the second case again.  If a call to func() is in
>some_other_source_file.cpp that includes someheader.h, i1 will refer
>to the first parameter.  If that function is cut from that header and
>pasted into the bottom of the file with the second definition, that
>same i1 will not refer to the third parameter.
>
>Frankly, unless you are prepared to require and enforce a "one
>prototype" rule, insisting that all prototypes of a function anywhere
>in a program, including its definition, must use exactly the same
>names, I don't see how this would be practical.  And I think a "one
>prototype" rule would break too much existing code to be seriously
>considered for addition to the standard.

No, there are plenty of other ways to deal with that problem, it is the
wider problem of leaking parameter names into the containing namespace
that is, IMO, a killer.


--
ACCU Spring Conference 2003 April 2-5
The Conference you cannot afford to miss
Check the details: http://www.accuconference.co.uk/
Francis Glassborow      ACCU

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dickie@acm.org (Garth A. Dickie)
Date: Wed, 29 Jan 2003 21:24:05 +0000 (UTC)
Raw View
jackklein@spamcop.net (Jack Klein) wrote in message news:<ttre3v094brkgnibfh6pvhillrq230ijt2@4ax.com>...
> ...
> you can have multiple
> prototypes in scope with different names for the same arguments.
> ...

Perhaps something similar to overload resolution, where it succeeds
unless there is ambiguity. So the function call

    func(.i1(1), .i2(2), .i3(3))

would compile successfully if all visible prototypes for func which
use the name i1 for an argument have that argument in the same
position.

In particular, this would be OK:

    int func(int, int, int);
    int func(int i1, int i2, int i3);
    func(.i1(1), .i2(2), .i3(3))

I would argue that we can even make the following be OK:

    int func(int, int, int);
    int func(int i1, int i2, int i3);
    int func(int x, int y, int z);
    func(.i1(1), .i2(2), .i3(3))

But that may be too much; perhaps it would be better to require that
all visible prototypes for func must use compatible names for each
argument.  Here non-empty names are compatible only if they are
identical, and an empty name is compatible with any non-empty name.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: fma@doe.carleton.ca (Shing-Fat Fred Ma)
Date: Thu, 30 Jan 2003 05:14:04 +0000 (UTC)
Raw View
This is alot more complicated than
I initially thought.  With backward
compatibility being a major issue,
and the fact that the prototypes and
source code can be separate.  I
think that resolving any conflicts
with further overloading may cause
more confusion, which would be
self defeating.  It works for verilog
because the protocol was defined
from the beginning.  Anyway, thanks
for the listen.

Fred

--
Fred Ma, fma@doe.carleton.ca
Carleton University, Dept. of Electronics
1125 Colonel By Drive, Ottawa, Ontario
Canada, K1S 5B6



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: philippe_mori@hotmail.com ("Philippe Mori")
Date: Thu, 30 Jan 2003 05:16:09 +0000 (UTC)
Raw View
>
> Perhaps something similar to overload resolution, where it succeeds
> unless there is ambiguity. So the function call
>
>     func(.i1(1), .i2(2), .i3(3))
>
> would compile successfully if all visible prototypes for func which
> use the name i1 for an argument have that argument in the same
> position.
>
> I would argue that we can even make the following be OK:
>
>     int func(int, int, int);
>     int func(int i1, int i2, int i3);
>     int func(int x, int y, int z);
>     func(.i1(1), .i2(2), .i3(3))
>
> But that may be too much; perhaps it would be better to require that
> all visible prototypes for func must use compatible names for each
> argument.  Here non-empty names are compatible only if they are
> identical, and an empty name is compatible with any non-empty name.
>

For me, I think that it would be OK as long as for all compatible
functions proto the same parameter name is not used at a different
position.

So the following would not be accepted:

    int func(int i1, int i2, int);
    int func(int, int, int i1);

Since i1 appears once at position 3 and one at position one for
the same prototype.

An overload could have some diffrence:

    int func(double, int i1, int i2)

Otherwise, it would be very difficult to have multiple overload...

Eventually, we may add the restriction that all name should come
from the same prototype...

For me, if no ambiguity are possible, then it should be allowed.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: danielgutson@hotmail.com (danielgutson@hotmail.com)
Date: Thu, 30 Jan 2003 06:19:21 +0000 (UTC)
Raw View
dickie@acm.org (Garth A. Dickie) wrote in message news:<a757534a.0301290521.52b1d1dc@posting.google.com>...
> jackklein@spamcop.net (Jack Klein) wrote in message news:<ttre3v094brkgnibfh6pvhillrq230ijt2@4ax.com>...
> > ...
> > you can have multiple
> > prototypes in scope with different names for the same arguments.
> > ...
>
> Perhaps something similar to overload resolution, where it succeeds
> unless there is ambiguity. So the function call
>
>     func(.i1(1), .i2(2), .i3(3))

I like this, and 'somthing' like VisualBasic has named parameters
since long time ago.

But, the only complain I have against having **only** this mechanism
(and no parameter defaulting as in my proposal using 'default'
keyword) is that, sometimes remembering the parameter name is as
useless as remembering its position in other situation.
For example: let's consider the 'inc' function:

   void inc(int& x)
   {  x++; }

who would ever care the name given to its parameter?

This is just an example, and not full applicable since there are no
default parameters (in fact, only one). But the same situation can
even exist with them.
Perhaps another example: drawing a circle:

void drawCircle( int radious = 1, int centerX = 0, int centerY = 0,
Color color = green);

Coming from previous libraries, one could be customed with the order;
the name is a matter of the implementer (radious ~ r ~ delta ~ ...;
color ~ colour ~ c; centerX ~ x0 ~ x; centerY ~ y0 ~ y);

So <sometimes> ordering is more important (or mnemonic) than names.

AGAIN: I'm not against this proposal; just saying that should be
complementary with the other (defaulting params). (complementary, but
mutual exclusive during function call).

In fact, if named parameters is implemented, then I think the function
programmer should be able to disable this feature (for example reusing
the 'explicit' keyword).

 Daniel.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dave@boost-consulting.com (David Abrahams)
Date: Thu, 30 Jan 2003 16:19:59 +0000 (UTC)
Raw View
francis.glassborow@ntlworld.com (Francis Glassborow) writes:

> But the serious problem is that we had good reasons for
> placing 'prototype' (quoted because there is no such
> term in C++, as C++ has a single syntax for declaring
> function names) names in their own scope; it prevents
> such names leaking out into global namespace. Proposals
> such as the above would change that and impact on the
> single most complicated (and, IMO, confused) aspect of
> C++, name look-up. That seriously worries me.
...
>
> No, there are plenty of other ways to deal with that
> problem, it is the wider problem of leaking parameter
> names into the containing namespace that is, IMO, a
> killer.
>

I have some serious problems with the assertion you seem to be making
that the proposal would cause parameter names to "leak out into the
containing namespace".  The proposed syntaxes all clearly delineate
these identifiers from names which refer to entities in the caller's
namespace, so it seems to me that there's absolutely no reason for us
to choose a specification which causes them to leak in any meaningful
way.  Can you justify or qualify your claim somehow?

Thanks,
Dave

--
                       David Abrahams
   dave@boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: francis.glassborow@ntlworld.com (Francis Glassborow)
Date: Thu, 30 Jan 2003 16:20:26 +0000 (UTC)
Raw View
In article <3E384FCF.E908FDE1@doe.carleton.ca>, Shing-Fat Fred Ma
<fma@doe.carleton.ca> writes
>This is alot more complicated than
>I initially thought.  With backward
>compatibility being a major issue,
>and the fact that the prototypes and
>source code can be separate.  I
>think that resolving any conflicts
>with further overloading may cause
>more confusion, which would be
>self defeating.  It works for verilog
>because the protocol was defined
>from the beginning.  Anyway, thanks
>for the listen.

And likewise, thanks for listening to the responses and reacting
sensibly to them (much in contrast to the way a proposer is reacting in
another active thread.). It often helps to have ideas like yours put up
for discussion exactly because it allows us to see the pros and cons. I
think many of us have a hankering after being able to provide named
arguments but with C++ the way it is the costs appear to be too high.



--
ACCU Spring Conference 2003 April 2-5
The Conference you cannot afford to miss
Check the details: http://www.accuconference.co.uk/
Francis Glassborow      ACCU

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: francis.glassborow@ntlworld.com (Francis Glassborow)
Date: Thu, 30 Jan 2003 19:52:46 +0000 (UTC)
Raw View
In article <u4r7rcukj.fsf@boost-consulting.com>, David Abrahams
<dave@boost-consulting.com> writes
>> No, there are plenty of other ways to deal with that
>> problem, it is the wider problem of leaking parameter
>> names into the containing namespace that is, IMO, a
>> killer.
>>
>
>I have some serious problems with the assertion you seem to be making
>that the proposal would cause parameter names to "leak out into the
>containing namespace".  The proposed syntaxes all clearly delineate
>these identifiers from names which refer to entities in the caller's
>namespace, so it seems to me that there's absolutely no reason for us
>to choose a specification which causes them to leak in any meaningful
>way.  Can you justify or qualify your claim somehow?

I can think of no other context in which we allow the position of a name
in a definition to give it different meanings.

--
ACCU Spring Conference 2003 April 2-5
The Conference you cannot afford to miss
Check the details: http://www.accuconference.co.uk/
Francis Glassborow      ACCU

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: fma@doe.carleton.ca (fred)
Date: Mon, 27 Jan 2003 22:55:27 +0000 (UTC)
Raw View
Hello,

Someone suggested posting my article
here....

Fred

-------- Original Message --------
Subject: Idea for self documenting parameter passing
Date: Sun, 26 Jan 2003 22:18:15 -0500
From: f <fma@doe.carleton.ca>
Reply-To: fma@doe.carleton.ca
Organization: Bell Sympatico
Newsgroups: comp.lang.c++

Hello,

I've got a beef about how parameters are passed in
C/C++.  The function's formal arguments are bound
to the informal arguments (for lack of a better word?)
supplied by the caller of the function.  The association
is made by the position of the arguments.  This has
always bugged me a bit because I recall fortran days,
where argument list would sprawl over many lines.  It
was easy to have misaslignment in positional
association.

C++ argument lists are not so long, but no we have
the complexity of overloaded functions, with different
argument lists.  So when you look at a piece of source
code, you're not really sure what function you're looking
at without going back to the documentation and
scanning carefully through the various forms of the
function.  For type conversion functions, I can uderstand
that this kind of  overloaded argument list is great and
good, but sometimes, the overloaded functions actually
perform different (though related) tasks depending on
how the function resolves.  Makes one kind of wonder
whether it might be better to just use a function with a
slightly different name so that the source code has
some kind of explicit documentation of what it's
exactly doing.

One compromise between using different functions
with different names vs different parameter lists is an
borrowed from the hardware description language
called Verilog.  There, the dominant instantion is the
instantiation of modules rather than functions; but, there
is still a formal and "informal" list of parameters.  The
difference I'd like to point out is that, with each
instantiation, the designer has to option of *explicitly*
associating the formal parameters with the informal ones.
Declaring an instance of a module is as follows:

     Module_Definition_Name    Instance_1 (
         .Formal_Param_1 ( Informal_Param_1 ) ,
         .Formal_Param_2 ( Informal_Param_2 ) ,
             :
             :
         .Formal_Param_N ( Informal_Param_N )
     ) ;

The occurance of the formal parameters in the
above instantiation does not have to be the same
as the order in the module definition.

Though explicit association of parameters is optional, I
never went back to positional association of parameters
after discovering the former.  Well, except to save space
sometimes, for short parameter lists.  But even then,
explicit association is great for self-documenting code,
or at least improved readability.  It also avoids the mistake
of associating an informal parameter with the wrong formal
parameter.

For the overloaded functions of C++, it would help the
programmer recognize more quickly how the function
resolves.  And added bonus is that the provision of
default argument values is not restricted to the formal
arguments at the tail end of the formal argument list.
How does this sound as a possible enhancement to
C++?

Fred

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]