Hacker News new | ask | show | jobs
by xenadu02 18 days ago
Not just this it is important to remember that there was no "aha!" moment where C was created whole-cloth by writing the first compiler in B then cross-compiling.

The language B was evolved in-place by adding new features, then editing the compiler source to make use of those new features, then repeating. They simply started calling it "New B". At some point the language had evolved sufficiently that they decided to call it C.

The semantics of arrays were inherited from B and simply never changed. Part of me suspects this was also because it was seen as "clever" at the time. Look ma, we let arrays turn into pointers! Isn't that clever?

When you look at pre-ANSI C function prototypes you wonder "where are the parameter types?" because there are none. The compiler didn't bother to check. Part of that was perhaps for implementation reasons but a big part of that was the feeling or culture inherited from B: in that language you just had words of memory. You were free to interpret any word of memory as any data type you liked. So duh of course it is up to you to decide how many parameters your function received and of what type. If the caller supplied a different number or different types? Don't do that.

If you are coming from that sort of world clever tricks like arrays decaying to pointers or automatically converting between data types and sizes seems perfectly natural. Anything C offers above and beyond that is an improvement from B after all.

2 comments

> Part of me suspects this was also because it was seen as "clever" at the time. Look ma, we let arrays turn into pointers! Isn't that clever?

It was intentional and functional. The idea was basically a primitive kind of polymorphism, which allowed for functions intended to act on arrays to accept any size of an array to be passed in. It was redundant with pointer arithmetic, but allowed for communication of intent without accidentally incurring a semantic unit of meaning. There's an interview where Ritchie talked about this.

Pascal's biggest misgiving was that it went the complete opposite route, where pointer arithmetic was disallowed and arrays did not decay. It also lacked any kind of polymorphism, and one of the biggest ergonomic painpoints ends up being that if your problem domain has non-uniform array sizes, you're in for a lot of annoying re-writing.

> When you look at pre-ANSI C function prototypes you wonder "where are the parameter types?" because there are none.

Actually pre-ANSI C technically didn't have function prototypes, ANSI C introduced them and it got them from C-with-classes. It did have function declarations though (which aren't the same thing)

Pedantics aside,

    f(a, b) { return a + b; }
This is fully typed, the parameters and return type default to int.

Fun fact:

    int f();
Does not declare a function with no parameters, but it does declare a function with an unknown number of parameters of unknown types. An empty parameter list in C is:

    int f(void);
In assembly languages, storage defined with a name turns into a pointer; like when you write some "load reg, name", instruction referencing that name, you are loading a pointer. The pointer is not stored anywhere; it turns into an immediate operand right in the instruction which is backpatched when the object file is linked.

The predecessor dialects of C were being silly to actually have a pointer word inside the declared array object; C kind of returned to the normal "assembly-like state of things" by treating a region of storage declared as an array as a base pointer, without that pointer being stored alongside the array.

BTW, in C23, int f(); is now a prototype meaning the same thing as void.
> Actually pre-ANSI C technically didn't have function prototypes,

Thanks, I completely forgot they weren't called prototypes originally.

Those decisions also make a lot of sense from the C-as-macro-assembler point of view (passing parameters puts values in the places defined by the calling convention, and taking parameters pulls them out) that has of course gradually faded over the year, being replaced by a rigorously defined (and undefined) abstract machine.