Declaring arguments to a function

Peter A. Friend octavian@corp.earthlink.net
Tue, 15 Jun 1999 11:46:49 -0700 (PDT)


On Tue, 15 Jun 1999, Jeremy Dunn wrote:

> The standard way of declaring a function and its arguments in C (or in
> a
> lot of languages) is a form like
> 
> return-type FUNCTION NAME (arg1,arg2,...,argN){
>         <program statements>
> }
> 
> We wish to do the following in defining arguments:
> 
> 1. We want to define the number of arguments.

Good.

> 2. We want to define the type of the arguments.

Even better.

> 3. We want to define default values if the argument position is present
> but empty.

I have no experience with this kind of functionality. I DO think the
default value idea is useful.

> 4. We want to define default values if the argument position is not
> present.

This makes we wince a bit. I think this would cause problems with
knowing which argument gets the default value and which gets the
specified value.

> 
> I propose a form something like
> 
> return-type FUNCTION NAME
>         (<# of arguments>,
>          <argument names>,
>          <argument types>,
>          <default values> (if any)
>         )
> {
>   <program statements>
> }
> 
> Let us discuss each part of the declaration one step at a time. I
> envision the number of arguments as  being declared as an integer as
> one
> would declare a string array in C where you must decide on a value. But
> what if I define 20 arguments and I need to put in 30? I will get to
> that later.

Why do we need to have the programmer state the number of arguments? To
me, this sounds like a job for the compiler. Even if there are variable
numbers of arguments, you would have to specify these optional
arguments in the function declaration, so the total should be
available. While C and Java folks like me are used to 0 based arrays,
making a programmer use this in a function declaration is asking for
off-by-one errors. Also, I think the name, type and default value
should all be grouped together. Making the arguments associative
arrays is confusing I think. We should be writing this language for
program writers, not compiler writers. :-)

But perhaps I have missed the point. I see a potential problem in
situations where you have two consecutive arguments of the same type,
but when the function is called one of the arguments is not present.
How do we know which of the arguments the supplied value applies to,
and which one gets the default value? Are you using the numeric indexes
to resolve the ambiguity?

> Declaring argument names is done by giving the name of the argument you
> are going to use in your program and then following it by the index of
> the argument position that is going to use that name. For instance, in
> a
> function of two arguments we could write either (Base,Power) without
> indexes if we have a name for every argument or we could write it as
> (Base(0),Power(1)) where we declare the indice. Suppose the 1st
> argument
> is named Base but we have several related arguments following it of the
> same type in our program? We could write (Base(0),Power(1-)) where the
> hyphen means that all arguments following index 0 are related somehow.
> The compiler would automatically number these extra argument names as
> Power1, Power2 and so on, and that is how we would call them in our
> program.
> 
> Defining the argument types is done in a list like (int, float, string)
> and so on for each argument. If all the arguments are of the same type
> then you could write (int) to have the type default to int for all of
> them. Suppose the first three arguments are type int and everything
> following those are type string? You would write that as
> (int(-2),string(3-)) where the statement means that arguments at list
> indexes from 0 to 2 are ints and the indexes from 3 onwards are of type
> string. Nonconsecutive indexes of the same type could be stated like
> (int(0,2,4),string(1,3)). (Simple eh?

Again, I am having trouble with the whole numeric indexing idea. My
take on this is borrowed from how zone files work. If you have a
resource record of this form:

www.domain.com. IN A 127.0.0.1
                IN A 127.0.0.2

A blank owner (the first item) defaults to the last explicitly stated
owner. Therefore, www.domain.com would have both 127.0.0.1 and
127.0.0.2 as IP addresses. My thought is that an argument declaration
without a type defaults to the last explicitly stated type. Whether
this provides more rope for hanging and reduces clarity I am not sure.
All I can see it saving is some typing. This could also be used to
handle the case where we have multiple arguments of the same type. We
state one, then leave the others empty, which means there are of the
same type as the last specified, and the name is the same but with the
numeric index tacked onto the end.

> Default values are equivalent to what one does with the "optional"
> statement in VB. In this case one declares the optional value and
> follows it with a bracketed list of the index values of the arguments
> it
> applies to. The index values for the arguments are numbered starting at
> 0. So if I wanted to declare that argument 3 defaults to 24 then I
> would
> write the statement (24(23)). If I wanted arguments 1 thru 4 to default
> to "A" and argument 5 onward to default to 2 then I would write
> ("A"(-3),2(5-)). I could also have written the start and end indexes
> explcitly as in ("A"(0-3),2(5-)). If the start index is missing it
> assumes that it is 0 and if the finish index is missing then it
> continues for all arguments after the first one. Naturally, one can
> choose nonconsecutive indexes as in a statement like ("A"(0,2,7)). One
> may not declare more than one optional value for a given index.

Again, I think the default value should be supplied adjacent to every
argument.

> Now we have three special commands in our language that are very useful
> in regards to all of this. These three functions have no arguments but
> return information that is very useful. The 1st function
> NumberOfArguments() basically counts the number of commas in the
> argument part of the function and adds one to give the total number of
> argument spaces that are defined by your statement. So if you wrote
> 
> FUNCTION(,,,,)
> 
> with nothing actually input into the statement then NumberOfArguments()
> would say there are 5 argument slots.
> 
> The 2nd function is called EmptyArguments(). This function looks at the
> previous function statement and gives a list of the argument indices
> that have nothing in them. In our example the list (0,1,2,3,4) would be
> returned.
> 
> The 3rd function is the complement to the previous and is called
> FullArguments(). This function returns a list of all indices that
> actually had some characters typed into them.
> This way of doing things gives us full argument control and enables us
> to do some things programatically that cannot be done in other
> languages.

This is totally beyond cool. (God, I sound like I was born in California...)

I think the ability to programmatically determine the number and type
of arguments supplied to your function at runtime is exceedingly
useful. My only concern is with space and speed. It seems that these
days with all of the information hiding going on and global variables
being evil we are supposed to be passing everything to functions
directly. This is fine, but the more arguments you have, the more stack
space you are going to require upon function entry and exit. This also
takes time. If we are going to be passing objects by reference (I
assume we are), then this really isn't an issue.

> How about an example? Let us write a function called Pwr() that returns
> the power of a number. Let the statement Pwr(s,t) be equivalent to the
> statement s^t. Let the function allow us to input up to 5 extra powers
> so that the statement Pwr(s,t,u,v,w,x) would be equivalent to
> (((((s^t)^u)^v)^w)^x). If the 1st argument "s" is empty then we wish
> the
> base to default to 2.718... the base of logarithms thus Pwr(,t) is
> equivalent to exp(t). If there is only argument then the function takes
> the square of whatever you put into it i.e. Pwr(x) is the same as x^2.
> If there are two arguments and the 2nd argument is empty then the power
> is assumed to be 3 i.e. Pwr(x,) is the same as x^3. If there is three
> or
> more arguments and any of the power arguments are empty then they are
> assumed to be 2. So the statement Pwr(s,,,) would be the same as
> (((s^2)^2)^2). We would write our function declaration like this:
> 
> double Pwr(<7,
>            (Base(0),Power(1-)),
>            (double),
>            (2.718(0),2(1-)),
>           )
> {
>   <program statements>
> }
> 
> Now using our special three functions we can access all the argument
> information we need to write a program that does all of the above.
> There
> is no way to write a function with ALL the features described without
> something like what I have described. I think my way is more intuitive,
> we do not have to deal with Paramarrays and such.
> 
> What about if I write an addition function that has 20 arguments
> defined
> and I supply 30? We must come back to stating the number of arguments.
> If I write <7 as in the example then the compiler assumes that I mean
> that the function must have less than 7 arguments. If I wrote =6 or
> just
> 6 instead then the compiler would assumed that I meant that the
> function
> must have 6 exactly 6 arguments present. In fact, we could even write
> ((>0,<7)) to declare that the function must have at least one argument
> present but no more than 6. If the argument number statement is empty
> then it assumes that the function requires NO arguments. I cannot
> declare simply >0 to imply a function that holds any number of
> arguments
> but must declare some limit. If I say <7 and input 8 arguments then I
> may input extra arguments but in the program I must use
> NumberOfArguments() to test the number and if it is more than 6 I must
> issue the equivalent of a VB Redim statement. Let us say I actually
> input 10 arguments, I would have a statement like
> 
>         N = NumberOfArguments()
>         If N > 6 {
>            ReDim Pwr(N)
>         }
> 
> In this case the name of the array is the name of the function. All
> extra arguments will take on the name and qualities of the last
> argument
> defined in the original function. If we define the number of arguments
> as =6 or just 6.
> 
> So, does anyone like any of this? Detest it? I await your insightful
> comments.

For the most part, I really like it. My only concerns are essentially
semantic, which we can discuss.

Peter

---
Software Engineer
EarthLink Network