If I had five wishes … to (GC)C maintainers

C puts the bread on the table for many of us, so every once in a while, when not just bashing C++, endulging in the awesomeness of Ruby, or wondering why PHP is still powering a good deal of the modern interwebs, the topic comes to C, its greatness, and how C99 is still not ubiquitous.

Personally I think, with the year being 2010 and all, just five humble features would make a whole lot of difference and put the language firmly in the 21st century, while not sacrificing any of the spirit of being a high-level assembly language. So here goes (in no particular order) …

Extended support for anonymous aggregates

C99′s anonymous aggregates are useful, for example when passing a one-off compound datatype to a function. What would be even more helpful would be the possibility to return an anonymous aggregate from a function, this would essentially allow returning multiple values:

struct { float width; float height; }
clutter_actor_get_size (ClutterActor *actor) {
  struct { float width; float height; } size;
  /* Fill size.width and size.height */
  return size;
}
[...]
struct { float width; float height; } size;
size = clutter_actor_get_size (actor);

This feature would be even more helpful with

Variable declarations using “auto”

When a variable is initialised in place it should be possible for today’s compilers to figure out the data type, there’s even things like the “L” suffix to numbers for specifying the desired range. Leveraging “auto” the above example would become a bit less verbose:

struct { float width; float height; }
clutter_actor_get_size (ClutterActor *actor) {
  struct { float width; float height; } size;
  /* Fill size.width and size.height */
  return size;
}
[...]
auto size = clutter_actor_get_size (actor);

Lambda functions

Along the lines of anonymous aggregates it would seem very natural to do lambda functions by basically “casting” a block of statements. The formal parameters would be derived from the “cast” operator. This approach, in my opinion, would be more natural to C than llvm’s block syntax using ^.

clutter_container_foreach (container,
                           (void (*)(ClutterActor *actor, gpointer data))
                           {
                             printf ("%s\n", clutter_actor_get_name (actor));
                           },
                           NULL);

Type extension

GObject based C code is typically interspersed with type casts, but this does not seem strictly necessary from a semantic point of view. A pointer to a compound instance in C is by definition also a pointer to the first attribute. It should be fairly straight forward to account for that in the compiler, and thus allow for implicit “upcasting”, i.e. assigning a pointer of a “derived” type to a pointer of type of an (first-member) embedded struct. There would be no need for the C compiler to warn about pointer types not matching, because the example is actually semantically correct.

/* Lots of GObject boilerplate code omitted. */
typedef struct {
  ClutterActor parent;
} FooActor;
[...]
FooActor *actor = foo_actor_new ();
clutter_actor_set_x (actor, 100.0);

An #import preprocessor directive

In this day and age it seems redundant having to type function signatures twice, once in the header and once again the the C file. It would be very handy if preprocessors could import symbols from other C files, without doing the verbatim insertion that is #include. For libraries which want to install headers I would imagine a compiler option that extracts definements and non-static symbols from a C file, possibly supporting filtering on prefixes, so the headers could be generated on the fly by the build system.

That might do for the next 30 years or so, I suppose.

3 Responses to “If I had five wishes … to (GC)C maintainers”

  1. Chris Lord says:

    Oddly, I find myself agreeing with almost all of this. Not so sure about the #import though, and auto could be a bit dangerous… (the example could’ve been made less verbose with a typedef, which you’d have probably wanted anyway)

  2. robsta says:

    Chris: but the idea is to avoid having to put stuff into the global namespace! Also having to invent and type definitions for all the various user-data aggregates is tedious and should be avoidable with anonymous aggregates and lambda functions.

  3. Neil Roberts says:

    You can almost do the first two with the ‘typeof’ operator in GCC like this:

    #include

    struct { float width; float height; }
    clutter_actor_get_size (int i)
    {
    /* Fill size.width and size.height */
    return (typeof (clutter_actor_get_size (3))) { 1, 2 };
    }

    int
    main (int argc, char **argv)
    {
    typeof (clutter_actor_get_size (3)) size;
    size = clutter_actor_get_size (3);

    printf (“%f %f\n”, size.width, size.height);

    return 0;
    }

    It seems like less effort just to make a typedef though because you’ve already had to write out the definition of the struct twice in your example (even with the auto keyword).

    I agree with the fourth one though; that would be really nice.