Keyword parameters

Discussion in 'C Programming' started by James Harris, Jun 1, 2014.

  1. James Harris

    James Harris Guest

    C function calls have positional parameters but in some cases keyword
    parameters would be useful such as with a sparse argument list. Is there any
    preferred way in C to implement something close to keyword parameters?

    James Harris, Jun 1, 2014
    1. Advertisements

  2. James Harris

    Stefan Ram Guest

    Instead of

    srand( 2227 );


    { unsigned int const seed = 2227; srand( seed ); }

    . Or, - more elaborated - instead of

    OpenWindow( 0, 0, 40, 40, 0, 1, "simple", WINDOWCLOSE |
    NULL, NULL, NULL, 0, 0, 0, 0 );

    use an interface that can be called like

    struct NewWindow NewWindow;

    NewWindow.LeftEdge = 0;
    NewWindow.TopEdge = 0;
    NewWindow.Width = 40;
    NewWindow.Height = 40;
    NewWindow.DetailPen = 0;
    NewWindow.BlockPen = 1;
    NewWindow.Title = "simple";
    NewWindow.IDCMPFlags = CLOSEWINDOW;
    NewWindow.Type = WBENCHSCREEN;
    NewWindow.FirstGadget = NULL;
    NewWindow.CheckMark = NULL;
    NewWindow.Screen = NULL;
    NewWindow.BitMap = NULL;
    NewWindow.MinWidth = 0;
    NewWindow.MinHeight = 0;
    NewWindow.MaxWidth = 0;
    NewWindow.MaxHeight = 0;

    OpenWindow( &NewWindow );
    Stefan Ram, Jun 1, 2014
    1. Advertisements

  3. James Harris

    BartC Guest

    That's only practical when you can design OpenWindow() yourself. You can't
    really ask MS to rewrite CreateWindow(), for example, to your specification!

    However MS do like to use this technique, of having to create and populate a
    struct to be passed as a parameter, in many of their interfaces, but it's
    even more of a pain that having to supply a dozen positional parameters.

    Keyword parameters would let you write your example as:

    OpenWindow(Width=40,Height=40, Blockpen=1, Title="Simple",

    This requires that parameters not specified will be set to some default
    value (eg. zero), otherwise keyword parameters are not so useful.

    I can't think of how to do this tidily in C without language support.
    BartC, Jun 1, 2014
  4. James Harris

    James Kuyper Guest

    C99 added two features named compound literals and designated
    initializers, that can be combined to gain essentially the same benefits
    that could be provided by keyword parameters:


    struct func_params{
    // Many parameters that you don't want to set.
    char *name;
    int age;
    double salary;
    int keyparamfunc(struct func_params in);

    Some other module:

    #include "keyparamfunc.h"

    int main(void)
    int j = keyparamfunc((struct func_params)
    {.salary=45933.25, .name="John Doe", .age=45});


    The code in main is essentially equivalent to:

    struct func_params temp={0};
    temp.salary = 45933.25; = "John Doe";
    temp.age = 45;
    int i = keyparamfunc(temp);

    Using compound literals is clumsier than using true keyword parameters,
    in that you must explicitly specify the struct type in the argument list
    of the function call.
    James Kuyper, Jun 1, 2014
  5. I don't know of a preferred way. There probably isn't one.

    But if passing a structure appeals as an almost but not quite
    approximation to something that this not entirely unlike named
    parameters, it is useful to know about C's compound literals and
    designated initialisers:

    f((f_args){ .size = 42, .type = "blue" });

    Every such function needs a corresponding struct (here I've assumed a
    typedef of it).

    I've never done this enough to know if it's worth it. I'm posting
    simply because these parts of C are little known.
    Ben Bacarisse, Jun 2, 2014
  6. Presumably you would write a list of string / argument pairs and pass them
    to the varargs engine, with a terminating nul.

    But I've never actually seen a C function written like that. You lose all the
    compile time type checking, of course.
    Malcolm McLean, Jun 2, 2014
  7. Several graphics libraries work like that, as they tend to have
    innumerable optional arguments. The first I remember was Suntools on
    1980s Sun Workstations. Rather than strings it used #defined or
    enumerated constants, and IIRC the constants contained bitfields
    identifying the type required for the corresponding value, so that
    they could be passed on without having to know all the possible

    -- Richard
    Richard Tobin, Jun 2, 2014
  8. James Harris

    James Harris Guest

    That's an option I thought of but using integer constants instead of
    strings. (I presume that by nul you mean a null pointer.)

    So where I understand you to mean

    f(pos0, pos1, NULL); /* Only positional, no keyword parms */
    f(pos0, pos1, "keyword0", kparm0, "keyword1", kparm1, NULL);

    I would have had

    f(pos0, pos1, 0); /* Only positional, no keyword parms */
    f(pos0, pos1, KWORD0, kparm0, KWORD1, kparm1, 0);
    Good point.

    James Harris, Jun 2, 2014
  9. James Harris

    Noob Guest

    Going on a tangent.

    When passing NULL to variadic functions, NULL must be cast to
    (void *) because some platforms define NULL as (unadorned) 0,
    thus it would be considered an int, in that context.

    Noob, Jun 2, 2014
  10. Actually it's probably better to use the convention that the empty string
    is the terminator, to avoid the NULL casting problem that Noob raised.

    I'd recommend using strings rather than defined integer constants. A
    maintaining programmer will be scratching his head wondering exactly
    what the integers mean and where they are defined. Strings are more
    intuitive, and they don't pollute namespace. If you're passing huge numbers
    of optional parameters, it's unlikely that the function is going to be
    a time critical call.
    Malcolm McLean, Jun 2, 2014
  11. James Harris

    James Kuyper Guest

    In principle, NULL could expand to an expression of any integer type,
    not just int. Of course, there is no obvious reason for it to expand
    into anything other than either 0 or (void*)0).
    James Kuyper, Jun 2, 2014
  12. James Harris

    Stefan Ram Guest

    One can sometimes transform this into

    keyword0( kparm0 );
    keyword1( kparm1 );
    f( pos0, pos1 );

    . The two keyword functions belong to the same library
    as f and prepare settings for the subsequent f call.

    An example in the standard library is the preparation
    of a rand() call by an srand() call.
    Stefan Ram, Jun 2, 2014
  13. That's common for graphics routines.
    But often you then need to be able to push and restore state to
    avoid knock-on effects for subsequent calls.
    Malcolm McLean, Jun 2, 2014
  14. NULL should be cast to whatever pointer type the function expects.
    Often that's going to be void*, but in this case it appears that the
    function expects char*.

    f(pos0, pos1, (char*)NULL); /* Only positional, no keyword parms */
    f(pos0, pos1, "keyword0", kparm0, "keyword1", kparm1, (char*)NULL);
    Keith Thompson, Jun 2, 2014
  15. You missed a parenthesis on ((void*)0).

    Incidentally, I've just thought of another peculiar but legal way to
    define NULL:

    #define NULL ('8'/'9')
    Keith Thompson, Jun 2, 2014
  16. James Harris

    James Harris Guest

    No solution would be perfect. How about

    WIN_Width, 40,
    WIN_Height, 40,
    WIN_BlockPen, 1,
    WIN_Title, "Simple",

    Genuine question. Is that good/bad/mediocre?

    James Harris, Jun 2, 2014
  17. James Harris

    James Harris Guest

    Set against that, names would be
    * fast
    * idiomatic
    * definable as header constants or as externs
    * checkable at compile or link time.

    I can see some value in using strings but, as well as being slower to match,
    errors in string parms might not show up until run time.
    Much of the time a keyword-based list of parms would be used sparsely so
    fewer parameters would be passed than those available.

    James Harris, Jun 2, 2014
  18. James Harris

    James Harris Guest

    I don't think I understand that. Do you mean that the keyword parameters
    would be stored in globals?

    James Harris, Jun 2, 2014
  19. You can't use strings for speed-critical code, agreed.
    C programmers do expect runtime micro-efficiency. But you're already being non-
    idiomatic by introducing named arguments.
    That's largely bad.

    You can just use "x" or "N" as a string. With integers and bit masks, it's got to be
    That's a slight advantage. You can't pass "X" or "x " accidentally. But mostly those bugs
    are easily caught when you parse the name / argument pairs.
    Malcolm McLean, Jun 2, 2014
  20. James Harris

    BartC Guest

    Well, when they added designated initialisers to the language, they could
    have thrown in keyword parameters too, as it's a similar sort of thing. I
    think the latter would be more useful.
    For C it's good. I've used the same approach at some time or other (often
    when needing to provide some options out of a large selection, not
    necessarily when using parameters).

    The disadvantages compared with proper keyword parameters:

    * You need to use the mechanisms for varargs, and specially designed
    function interfaces (you can't apply directly to existing functions)

    * There are overheads with processing the list of pairs, and assembling the
    parameters properly.

    * There is no compile-time checking of parameter names and argument types,
    or whether you've passed the same parameter twice for example.

    * You can't mix positional and keyword parameters (except I think by
    specifying a fixed number of positional parameters, although that might
    depend on how varargs works, and the order they are pushed).

    (Keyword parameters can be applied any function, including existing library
    functions (they just need named parameters, but that can be arranged); there
    are no extra overheads involved; there would be compile-time checking; and
    can have positional parameters as well. There would usually also be a
    mechanism to specify a default value.)
    BartC, Jun 2, 2014
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.