In the case of foreach, it's simple to be sure, and I'm pretty fine with calling foreach "syntactic sugar". Even something as simple as function composition breaks down a bit in C. You can manage it, but you're either not really using C anymore (writing out machine code in memory and treating it as a function, which is going to be tremendously compiler and architecture specific) or you're not really dealing with C functions anymore (passing around a structure that stores the things to compose, "calling" that function with a separate "apply" function).
Yes, you can ultimately write all of Haskell in C and code at the higher level, exceedingly verbosely, but to say that's "just syntactic sugar" would be absurd - "fundamentally all these languages are Turing equivalent" already encapsulates that observation, there's nothing new the notion of "just syntactic sugar" is adding.
Typically I restrict "just syntactic sugar" for things that are simple transformations that can be done locally. The archetypical example being array syntax in C, which can be described more precisely by a syntactic transformation than a semantic operation:
Given:
char *c = "abcd";
int i = 2;
It turns out that:
a[i] = *(a + i)
but that's equivalent, by commutativity of +, to:
*(i + a)
and so, counter-intuitively if you're thinking of [] as a semantic "array indexing" operation, you get the same results with:
> In the case of foreach, it's simple to be sure, and I'm pretty fine with calling foreach "syntactic sugar".
Yeah, I was responding specifically to the "foreach" and specific things layered on top of foreach, which are fairly straightforward in most popular non-FP languages.
> Even something as simple as function composition breaks down a bit in C.
Quite. No argument there. At least with standard C. (I think Clang and GNU C both have extensions -- but not the same ones -- that make this reasonably straightforward in simple cases, but still much less elegant than, say, Haskell.)
Yes, you can ultimately write all of Haskell in C and code at the higher level, exceedingly verbosely, but to say that's "just syntactic sugar" would be absurd - "fundamentally all these languages are Turing equivalent" already encapsulates that observation, there's nothing new the notion of "just syntactic sugar" is adding.
Typically I restrict "just syntactic sugar" for things that are simple transformations that can be done locally. The archetypical example being array syntax in C, which can be described more precisely by a syntactic transformation than a semantic operation:
Given:
It turns out that: but that's equivalent, by commutativity of +, to: and so, counter-intuitively if you're thinking of [] as a semantic "array indexing" operation, you get the same results with: