Live data from Hacker News

How to interpret complex C/C++ declarations (2004)

codeproject.com

1–10 of 14 posts

Re: How to interpret complex C/C++ declarations (2004)

#4
I find complex Scala declarations much harder to parse. Have a look at these examples:

def scanLeft[B, That](z: B)(op: (B, A) ⇒ B)(implicit bf: CanBuildFrom[Iterable[A], B, That]): That

implicit def flatten5[A, B, C, D, E, F](f: (A, B, C, D, E) ⇒ F): ((ImplicitConversions.this)#~[(ImplicitConversions.this)#~[(ImplicitConversions.this)#~[(ImplicitConversions.this)#~[A, B], C], D], E]) ⇒ F

implicit def flatten5[A, B, C, D, E, F](f: (A, B, C, D, E) ⇒ F): (~[~[~[~[A, B], C], D], E]) ⇒ F

These are, thankfully, exceptions and most declarations are easier to read, nevertheless, as a Scala beginner, it takes me quite some time parsing such a declaration when I intend to utilize the function in question. But that's probably the price to pay for complex static typing.

Re: How to interpret complex C/C++ declarations (2004)

#6

I find complex Scala declarations much harder to parse. Have a look at these examples: def scanLeft[B, That](z: B)(op: (B, A) ⇒ B)(implicit bf: CanBuildFrom[Iterable[A], B, That]): That implicit def flatten5[A, B, C, D, E, F](f: (A, B, C, D, E) ⇒ F): ((ImplicitConversions.this)#~[(ImplicitConversions.this)#~[(ImplicitConversions.this)#~[(ImplicitConversions.this)#~[A, B], C], D], E]) ⇒ F implicit def flatten5[A, B, C…

What does the tildes do in `(~[~[~[~[A, B], C], D], E])`?

Re: How to interpret complex C/C++ declarations (2004)

#7
post #6

I find complex Scala declarations much harder to parse. Have a look at these examples: def scanLeft[B, That](z: B)(op: (B, A) ⇒ B)(implicit bf: CanBuildFrom[Iterable[A], B, That]): That implicit def flatten5[A, B, C, D, E, F](f: (A, B, C, D, E) ⇒ F): ((ImplicitConversions.this)#~[(ImplicitConversions.this)#~[(ImplicitConversions.this)#~[(ImplicitConversions.this)#~[A, B], C], D], E]) ⇒ F implicit def flatten5[A, B, C…

What does the tildes do in `(~[~[~[~[A, B], C], D], E])`?

It's a wrapper over a sequence of matches: http://www.scala-lang.org/api/current/#scala.util.parsing.co...

Given p1: Parser[A] and p2: Parser[B], a parser composed with p1 ~ p2 will have type Parser[~[A, B]]. The successful result of the parser can be extracted from this case class.

In this case it will use the [[[[A,B] C] D] E] sequence to compose A,B,C,D,E together in order to produce F (A-F are types). At least if I understand things correctly, I've never used flatten5.

Re: How to interpret complex C/C++ declarations (2004)

#8
post #5

Yup, we need periodic reminders (and Koenig's C Traps/Pitfalls book, which was published in, yes, 1989. http://ieng9.ucsd.edu/~cs30x/rt_lt.rule.html https://news.ycombinator.com/item?id=5079787

My memory may be faulty, but isn't this also a significant material in K&R? That would make it almost as old as dirt.

Re: How to interpret complex C/C++ declarations (2004)

#9
The main things to remember is that declaration mirrors use, and you don't actually directly declare the type of the variable, you declare the type of the expression that the declaration mirrors.

  // x has type int
  int x;

  // the expression *x has type int
  // -> x is something that, when dereferenced, yields an int 
  // -> x is a pointer to int
  int *x;

  // x[n] has type int for some integer n 
  // -> x is something, when applied the array subscript operator to, yields an int
  // -> x is an array of ints
  int x[5];

  // x() has type int 
  // -> x is something that, when called, returns int
  // -> x is a function returning int
  int x();

  // *x() has type int 
  // -> by operator precedence, calling x, then applying *, yields an int
  // -> x is a function returning a pointer to int
  int *x();

  // (*x)() has type int
  // -> dereferencing x, then calling the result, yields an int
  // -> x is a pointer to a function returning int.
  int (*x)();

Re: How to interpret complex C/C++ declarations (2004)

#10
Doesn't mention the standard "read it backwards to get the type", and consequently recommends "const int" over the superior "int const".

int * const p;

Is clearly a pointer to pointer to constant pointer to int. (Hint: read from right to left). This is made easier if you always put the const modifier to the right when it is optional.

And just never, ever mix commas with pointer declarations.

Post reply on HN