Changeset d02d223


Ignore:
Timestamp:
Jul 25, 2024, 4:59:34 PM (4 months ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
master
Children:
3cb693c
Parents:
878b1385
Message:

rewrite section on default/named parameters

File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/user/user.tex

    r878b1385 rd02d223  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Tue Jul  9 10:43:40 2024
    14 %% Update Count     : 6887
     13%% Last Modified On : Thu Jul 25 16:53:43 2024
     14%% Update Count     : 6945
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    15981598and implicitly opened \emph{after} a function-body open, to give them higher priority:
    15991599\begin{cfa}
    1600 void f( S & s, char ®c® ) with ( s ) ®with( §\emph{\R{params}}§ )® { // syntax not allowed, illustration only
     1600void f( S & s, char ®c® ) with ( s ) ®with( §\emph{\R{params}}§ )® { // syntax disallowed, illustration only
    16011601        s.c = ®c;®  i = 3;  d = 5.5;
    16021602}
     
    33133313for example, the following is incorrect:
    33143314\begin{cfa}
    3315 * [ int x ] f () fp; §\C{// routine name "f" is not allowed}§
    3316 \end{cfa}
    3317 
    3318 
    3319 \section{Named and Default Arguments}
    3320 
    3321 Named\index{named arguments}\index{arguments!named} and default\index{default arguments}\index{arguments!default} arguments~\cite{Hardgrave76}\footnote{
     3315* [ int x ] f () fp; §\C{// routine name "f" is disallowed}§
     3316\end{cfa}
     3317
     3318
     3319\section{Default and Named Parameter}
     3320
     3321Default\index{default parameter}\index{parameter!default} and named\index{named parameter}\index{parameter!named} parameters~\cite{Hardgrave76}\footnote{
    33223322Francez~\cite{Francez77} proposed a further extension to the named-parameter passing style, which specifies what type of communication (by value, by reference, by name) the argument is passed to the routine.}
    33233323are two mechanisms to simplify routine call.
    3324 Both mechanisms are discussed with respect to \CFA.
    3325 \begin{description}
    3326 \item[Named (or Keyword) Arguments:]
    3327 provide the ability to specify an argument to a routine call using the parameter name rather than the position of the parameter.
    3328 For example, given the routine:
    3329 \begin{cfa}
    3330 void p( int x, int y, int z ) {...}
    3331 \end{cfa}
    3332 a positional call is:
    3333 \begin{cfa}
    3334 p( 4, 7, 3 );
    3335 \end{cfa}
    3336 whereas a named (keyword) call may be:
    3337 \begin{cfa}
    3338 p( z : 3, x : 4, y : 7 );  §\C{// rewrite \(\Rightarrow\) p( 4, 7, 3 )}§
    3339 \end{cfa}
    3340 Here the order of the arguments is unimportant, and the names of the parameters are used to associate argument values with the corresponding parameters.
    3341 The compiler rewrites a named call into a positional call.
    3342 The advantages of named parameters are:
    3343 \begin{itemize}
    3344 \item
    3345 Remembering the names of the parameters may be easier than the order in the routine definition.
    3346 \item
    3347 Parameter names provide documentation at the call site (assuming the names are descriptive).
    3348 \item
    3349 Changes can be made to the order or number of parameters without affecting the call (although the call must still be recompiled).
    3350 \end{itemize}
    3351 
    3352 Unfortunately, named arguments do not work in C-style programming-languages because a routine prototype is not required to specify parameter names, nor do the names in the prototype have to match with the actual definition.
    3353 For example, the following routine prototypes and definition are all valid.
    3354 \begin{cfa}
    3355 void p( int, int, int ); §\C{// equivalent prototypes}§
    3356 void p( int x, int y, int z );
    3357 void p( int y, int x, int z );
    3358 void p( int z, int y, int x );
    3359 void p( int q, int r, int s ) {} §\C{// match with this definition}§
    3360 \end{cfa}
    3361 Forcing matching parameter names in routine prototypes with corresponding routine definitions is possible, but goes against a strong tradition in C programming.
    3362 Alternatively, prototype definitions can be eliminated by using a two-pass compilation, and implicitly creating header files for exports.
    3363 The former is easy to do, while the latter is more complex.
    3364 
    3365 Furthermore, named arguments do not work well in a \CFA-style programming-languages because they potentially introduces a new criteria for type matching.
    3366 For example, it is technically possible to disambiguate between these two overloaded definitions of ©f© based on named arguments at the call site:
    3367 \begin{cfa}
    3368 int f( int i, int j );
    3369 int f( int x, double y );
    3370 
    3371 f( j : 3, i : 4 ); §\C{// 1st f}§
    3372 f( x : 7, y : 8.1 ); §\C{// 2nd f}§
    3373 f( 4, 5 );  §\C{// ambiguous call}§
    3374 \end{cfa}
    3375 However, named arguments compound routine resolution in conjunction with conversions:
    3376 \begin{cfa}
    3377 f( i : 3, 5.7 ); §\C{// ambiguous call ?}§
    3378 \end{cfa}
    3379 Depending on the cost associated with named arguments, this call could be resolvable or ambiguous.
    3380 Adding named argument into the routine resolution algorithm does not seem worth the complexity.
    3381 Therefore, \CFA does \emph{not} attempt to support named arguments.
    3382 
    3383 \item[Default Arguments]
    3384 provide the ability to associate a default value with a parameter so it can be optionally specified in the argument list.
    3385 For example, given the routine:
    3386 \begin{cfa}
    3387 void p( int x = 1, int y = 2, int z = 3 ) {...}
    3388 \end{cfa}
    3389 the allowable positional calls are:
    3390 \begin{cfa}
    3391 p(); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 3 )}§
    3392 p( 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 2, 3 )}§
    3393 p( 4, 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 4, 3 )}§
    3394 p( 4, 4, 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 4, 4 )}§
    3395 // empty arguments
    3396 p(  , 4, 4 ); §\C{// rewrite \(\Rightarrow\) p( 1, 4, 4 )}§
    3397 p( 4,  , 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 2, 4 )}§
    3398 p( 4, 4,   ); §\C{// rewrite \(\Rightarrow\) p( 4, 4, 3 )}§
    3399 p( 4,  ,   ); §\C{// rewrite \(\Rightarrow\) p( 4, 2, 3 )}§
    3400 p(  , 4,   ); §\C{// rewrite \(\Rightarrow\) p( 1, 4, 3 )}§
    3401 p(  ,  , 4 ); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 4 )}§
    3402 p(  ,  ,   ); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 3 )}§
    3403 \end{cfa}
     3324
     3325
     3326\subsection{Default}
     3327
     3328A default parameter provides the ability to associate a default value with a parameter so it can be optionally specified in the argument list.
     3329For example, given the routine prototype:
     3330\begin{cfa}
     3331void f( int x ®= 1®, int y ®= 2®, int z ®= 3® );
     3332\end{cfa}
     3333allowable calls are:
     3334\begin{cquote}
     3335\setlength{\tabcolsep}{0.75in}
     3336\begin{tabular}{@{}ll@{}}
     3337\textbf{positional arguments} & \textbf{empty arguments} \\
     3338\begin{cfa}
     3339f(); §\C[0.75in]{// rewrite \(\Rightarrow\) f( 1, 2, 3 )}§
     3340f( 4 ); §\C{// rewrite \(\Rightarrow\) f( 4, 2, 3 )}§
     3341f( 4, 4 ); §\C{// rewrite \(\Rightarrow\) f( 4, 4, 3 )}§
     3342f( 4, 4, 4 ); §\C{// rewrite \(\Rightarrow\) f( 4, 4, 4 )}\CRT§
     3343
     3344
     3345
     3346\end{cfa}
     3347&
     3348\begin{cfa}
     3349f( ?, 4, 4 ); §\C[1.0in]{// rewrite \(\Rightarrow\) f( 1, 4, 4 )}§
     3350f( 4, ?, 4 ); §\C{// rewrite \(\Rightarrow\) f( 4, 2, 4 )}§
     3351f( 4, 4, ? ); §\C{// rewrite \(\Rightarrow\) f( 4, 4, 3 )}§
     3352f( 4, ?, ? ); §\C{// rewrite \(\Rightarrow\) f( 4, 2, 3 )}§
     3353f( ?, 4, ? ); §\C{// rewrite \(\Rightarrow\) f( 1, 4, 3 )}§
     3354f( ?, ?, 4 ); §\C{// rewrite \(\Rightarrow\) f( 1, 2, 4 )}§
     3355f( ?, ?, ? ); §\C{// rewrite \(\Rightarrow\) f( 1, 2, 3 )}\CRT§
     3356\end{cfa}
     3357\end{tabular}
     3358\end{cquote}
    34043359Here the missing arguments are inserted from the default values in the parameter list.
    34053360The compiler rewrites missing default values into explicit positional arguments.
     
    34083363\item
    34093364Routines with a large number of parameters are often very generalized, giving a programmer a number of different options on how a computation is performed.
    3410 For many of these kinds of routines, there are standard or default settings that work for the majority of computations.
     3365For many of these routines, there are standard or default settings that work for the majority of computations.
    34113366Without default values for parameters, a programmer is forced to specify these common values all the time, resulting in long argument lists that are error prone.
    34123367\item
     
    34223377Instead, a default value is used, which may not be the programmer's intent.
    34233378
    3424 Default values may only appear in a prototype versus definition context:
    3425 \begin{cfa}
    3426 void p( int x, int y = 2, int z = 3 ); §\C{// prototype: allowed}§
    3427 void p( int, int = 2, int = 3 ); §\C{// prototype: allowed}§
    3428 void p( int x, int y = 2, int z = 3 ) {} §\C{// definition: not allowed}§
     3379Default parameters may only appear in a prototype versus definition context:
     3380\begin{cfa}
     3381void f( int x, int y = 2, int z = 3 );  §\C{// prototype: allowed}§
     3382void f( int, int = 2, int = 3 );                §\C{// prototype: allowed}§
     3383void f( int x, int y = 2, int z = 3 ) ®{}® §\C{// definition: disallowed}§
    34293384\end{cfa}
    34303385The reason for this restriction is to allow separate compilation.
    3431 Multiple prototypes with different default values is an error.
    3432 \end{description}
    3433 
    3434 Ellipse (``...'') arguments present problems when used with default arguments.
    3435 The conflict occurs because both named and ellipse arguments must appear after positional arguments, giving two possibilities:
    3436 \begin{cfa}
    3437 p( /* positional */, ... , /* named */ );
    3438 p( /* positional */, /* named */, ... );
    3439 \end{cfa}
    3440 While it is possible to implement both approaches, the first possibly is more complex than the second, \eg:
    3441 \begin{cfa}
    3442 p( int x, int y, int z, ... );
    3443 p( 1, 4, 5, 6, z : 3, y : 2 ); §\C{// assume p( /* positional */, ... , /* named */ );}§
    3444 p( 1, z : 3, y : 2, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§
    3445 \end{cfa}
    3446 In the first call, it is necessary for the programmer to conceptually rewrite the call, changing named arguments into positional, before knowing where the ellipse arguments begin.
    3447 Hence, this approach seems significantly more difficult, and hence, confusing and error prone.
    3448 In the second call, the named arguments separate the positional and ellipse arguments, making it trivial to read the call.
    3449 
    3450 The problem is exacerbated with default arguments, \eg:
    3451 \begin{cfa}
    3452 void p( int x, int y = 2, int z = 3... );
    3453 p( 1, 4, 5, 6, z : 3 ); §\C{// assume p( /* positional */, ... , /* named */ );}§
    3454 p( 1, z : 3, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§
    3455 \end{cfa}
    3456 The first call is an error because arguments 4 and 5 are actually positional not ellipse arguments;
    3457 therefore, argument 5 subsequently conflicts with the named argument z : 3.
    3458 In the second call, the default value for y is implicitly inserted after argument 1 and the named arguments separate the positional and ellipse arguments, making it trivial to read the call.
    3459 For these reasons, \CFA requires named arguments before ellipse arguments.
    3460 Finally, while ellipse arguments are needed for a small set of existing C routines, like ©printf©, the extended \CFA type system largely eliminates the need for ellipse arguments \see{\VRef{s:Overloading}}, making much of this discussion moot.
     3386Multiple prototypes with different default values is undefined.
    34613387
    34623388Default arguments and overloading \see{\VRef{s:Overloading}} are complementary.
     
    34663392\multicolumn{1}{c@{\hspace{3em}}}{\textbf{default arguments}}   & \multicolumn{1}{c}{\textbf{overloading}}      \\
    34673393\begin{cfa}
    3468 void p( int x, int y = 2, int z = 3 ) {...}
     3394void f( int x, int y = 2, int z = 3 ) {...}
    34693395
    34703396
     
    34723398&
    34733399\begin{cfa}
    3474 void p( int x, int y, int z ) {...}
    3475 void p( int x ) { p( x, 2, 3 ); }
    3476 void p( int x, int y ) { p( x, y, 3 ); }
     3400void f( int x, int y, int z ) {...}
     3401void f( int x ) { f( x, 2, 3 ); }
     3402void f( int x, int y ) { f( x, y, 3 ); }
    34773403\end{cfa}
    34783404\end{tabular}
    34793405\end{cquote}
    34803406the number of required overloaded routines is linear in the number of default values, which is unacceptable growth.
    3481 In general, overloading should only be used over default arguments if the body of the routine is significantly different.
     3407In general, overloading is used over default parameters, if the body of the routine is significantly different.
    34823408Furthermore, overloading cannot handle accessing default arguments in the middle of a positional list, via a missing argument, such as:
    34833409\begin{cfa}
    3484 p( 1, /* default */, 5 ); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 5 )}§
    3485 \end{cfa}
    3486 
    3487 Given the \CFA restrictions above, both named and default arguments are backwards compatible.
     3410f( 1, ?, 5 );                                                   §\C{// rewrite \(\Rightarrow\) f( 1, 2, 5 )}§
     3411\end{cfa}
     3412
     3413
     3414\subsection{Named (or Keyword)}
     3415
     3416A named (keyword) parameter provides the ability to specify an argument to a routine call using the parameter name rather than the position of the parameter.
     3417For example, given the routine prototype:
     3418\begin{cfa}
     3419void f( int ®?®x, int ®?®y, int ®?®z );
     3420\end{cfa}
     3421allowable calls are:
     3422\begin{cfa}
     3423f( ?x = 3, ?y = 4, ?z = 5 );                    §\C{// rewrite \(\Rightarrow\) f( 3, 4, 5 )}§
     3424f( ?y = 4, ?z = 5, ?x = 3 );                    §\C{// rewrite \(\Rightarrow\) f( 3, 4, 5 )}§
     3425f( ?z = 5, ?x = 3, ?y = 4 );                    §\C{// rewrite \(\Rightarrow\) f( 3, 4, 5 )}§
     3426f( ?x = 3, ?z = 5, ?y = 4 );                    §\C{// rewrite \(\Rightarrow\) f( 3, 4, 5 )}§
     3427\end{cfa}
     3428Here the ordering of the the parameters and arguments is unimportant, and the names of the parameters are used to associate argument values with the corresponding parameters.
     3429The compiler rewrites a named call into a positional call.
     3430Note, the syntax ©?x = 3© is necessary for the argument, because ©x = 3© has an existing meaning, \ie assign ©3© to ©x© and pass the value of ©x©.
     3431The advantages of named parameters are:
     3432\begin{itemize}
     3433\item
     3434Remembering the names of the parameters may be easier than the order in the routine definition.
     3435\item
     3436Parameter names provide documentation at the call site (assuming the names are descriptive).
     3437\item
     3438Changes can be made to the order or number of parameters without affecting the call (although the call must still be recompiled).
     3439\end{itemize}
     3440
     3441Named parameters may only appear in a prototype versus definition context:
     3442\begin{cfa}
     3443void f( int  x, int ?y, int ?z );               §\C{// prototype: allowed}§
     3444void f( int ?x, int , int ?z );                 §\C{// prototype: allowed}§
     3445void f( int x, int ?y, int ?z ) ®{}®    §\C{// definition: disallowed}§
     3446\end{cfa}
     3447The reason for this restriction is to allow separate compilation.
     3448Multiple prototypes with different positional parameter names is an error.
     3449
     3450The named parameter is not part of type resolution;
     3451the type of the expression assigned to the named parameter affects type resolution.
     3452\begin{cfa}
     3453int f( int ?i, int ?j );
     3454int f( int ?i, double ?j );
     3455f( ?j = 3, ?i = 4 );                                    §\C{// 1st f}§
     3456f( ?i = 7, ?j = 8.1 );                                  §\C{// 2nd f}§
     3457\end{cfa}
     3458
     3459
     3460\subsection{Mixed Default/Named}
     3461
     3462Default and named parameters can be intermixed and named parameters can have a default value.
     3463For example, given the routine prototype:
     3464\begin{cfa}
     3465void f( int x, int y ®= 1®, int ®?®z ®= 2® );
     3466\end{cfa}
     3467allowable calls are:
     3468\begin{cfa}
     3469f( 3 );                                                                 §\C{// rewrite \(\Rightarrow\) f( 3, 1, 2 )}§
     3470f( 3, 4 );                                                              §\C{// rewrite \(\Rightarrow\) f( 3, 4, 2 )}§
     3471f( 3, ?z = 5 );                                                 §\C{// rewrite \(\Rightarrow\) f( 3, 1, 5 )}§
     3472f( 3, 4, ?z = 5 );                                              §\C{// rewrite \(\Rightarrow\) f( 3, 4, 5 )}§
     3473f( ?z = 5, 3 );                                                 §\C{// rewrite \(\Rightarrow\) f( 3, 1, 5 )}§
     3474f( 3, ?z = 5, 4 );                                              §\C{// rewrite \(\Rightarrow\) f( 3, 4, 5 )}§
     3475\end{cfa}
     3476Finally, the ellipse (``...'') parameter must appear after positional and named parameters in a routine prototype.
     3477\begin{cfa}
     3478void f( int i = 1, int ?j = 2, ®...® );
     3479\end{cfa}
     3480
     3481\CFA named and default arguments are backwards compatible with C.
    34883482\Index*[C++]{\CC{}} only supports default arguments;
    34893483\Index*{Ada} supports both named and default arguments.
Note: See TracChangeset for help on using the changeset viewer.