Hacker News new | ask | show | jobs
by palotasb 528 days ago
The spiral rule works only if there is no pointer to pointer or array of array in the type. In other words it is an incorrect rule. But take this for example:

        +----------------------------+
        | +-----------------------+  |
        | | +------------------+  |  |
        | | | +-------------+  |  |  |
        | | | | +--------+  |  |  |  |
        | | | | |  +--+  |  |  |  |  |
        | | | | |  ^  |  |  |  |  |  |
    int * * ¦ ¦ ¦ VAR[1][2][3] |  |  |
     ^  | | | | |     |  |  |  |  |  |
     |  | | | | +-----+  |  |  |  |  |
     |  | | | +----------+  |  |  |  |
     |  | | +---------------+  |  |  |
     |  | ---------------------+  |  |
     |  +-------------------------+  |
     +-------------------------------+
The type of VAR is a [1-element] array of [2-element] array of [3-element] array of pointer to pointer to ints. I drew a spiral that passes through each specifier in the correct order. To make the spiral correct it has to skip the pointer specifiers in the first three loops. This is marked by ¦.

The Right-Left Rule is quoted less frequently on HN but it's a correct algorithm for deciphering C types: http://cseweb.ucsd.edu/~ricko/rt_lt.rule.html

The spiral rule can be modified to process all array specifiers before all pointer specifiers, but then you'd have to specify that the order to do so is right and then left. At that point it's just the Right-Left Rule.

4 comments

I've found that 'declaration follows use' is actually the easiest way to understand C type declarations. The only annoying to remember thing is which way the various type specifiers like const bind.
In physics that usually means that we are missing something in the ¦'s. Like these hypothetical/imaginary "arr" keywords, look:

  int ** arr arr arr VAR[1][2][3];
By introducing these virtual storage kind specifiers, the spiral model works! It becomes apparent that these specifiers are actually real, cause the model wouldn't be consistent otherwise, and there's so much evidence for it all over the C codebases. We just tend to see the "real" part of it (sigh, stuck forever with that legacy terminology), while this is what actually happens:

  long double _Complex ** arr arr arr VAR[1][-1][sqrtl(-1)];
which is naturally homomorphic to most C compilations.

(spoiler for those who need it: jk)

My own interpretation (which effectively matches the right-left rule, at least algorithmically) is that, (), [], and * are operators, which have different semantics at the declaration vs the 'usage/expression' level, where:

() and [] are right-associative unary type-operators, with high fixity, (or equivalently, binary type-operators when () or [] have arguments)

and * is a binary type-operator, with low fixity (i.e. lower than () or [] ), where the 'left' argument is effectively the context that's left after removing the asterisk and the 'right' argument (rather than what's to the left of the asterisk in a purely 'anatomical 'sense')

(whereas, at the expression level, * is a unary value-operator instead, while () and [] behave the same as in their type-form, except acting as value-operators instead)

If you're going to adjust willy-nilly on which loop of the spiral a given element appears, then it's not much of a rule, isn't it? I mean, why not write this?

        +----------------------------+
        | +-----------------------+  |
        | | +------------------+  |  |
        | | | +-------------+  |  |  |
        | | | | +--------+  |  |  |  |
        | | | | |  +--+  |  |  |  |  |
        | | | | |  ^  |  |  |  |  |  |
    int ¦ ¦ * * ¦ VAR ¦ [1] ¦ [2][3] ¦
     ^  | | | | |     |  |  |  |  |  |
     |  | | | | +-----+  |  |  |  |  |
     |  | | | +----------+  |  |  |  |
     |  | | +---------------+  |  |  |
     |  | ---------------------+  |  |
     |  +-------------------------+  |
     +-------------------------------+
I think that's their point. I read it as explaining why the rule doesn't work, rather than defending it.