Gedanken: A Simple Typeless Language (1970) [pdf]
pdf.yt
pdf.yt
int f(float x) {
return *(int *)x;
} int f(float x) {
return *(int *)&x;
}
On one hand you demonstrate that C cares a tiny little bit about type, but mostly because of implicit numeric conversions rather than any serious attempt at stropping you from bad casting.I do agree with the point that C isn't "typeless" in any real sense, though.
C does not refuse to let you cast from a non-pointer to a pointer either, though. It just forces you to be slightly more devious in this case:
return *(int **)&x;
Though I think the implicit conversions that force some of these contortions (e.g. "(int *)(int)x" compiles, but does not return an integer pointer with the address equal to the bit pattern of "x" interpreted as an integer, but the integer portion of the float reinterpreted as a pointer) are more convincing demonstration that C is not typeless in a meaningful way in my opinion, as they also mean identical statements will give different results depending on the types of the variables.You can add a third one to that list: safety.
C has types in the sense that it allows you to do abstraction, and type checking, but it doesn't enforce safety.
2/3 doesn't seem bad to me, especially for a systems language.
I'd say that Typescript is in a similar position, you can cast anything to any type you want and there is no runtime check to stop you, but it helps you add structure to your code.
Types do very much matter in these languages in practice, since you want to very much want to avoid writing a giant mess.
While C does not give you safety, the typing is important for ease of access to members of structures, for example, and for deciding the number of bits or bytes to operate on, and for deciding layout of a type.
The moment you go fully typeless, you suddenly need to be explicit about layout, size and signedness far more places.
This before I went overboard and started layering a Ruby compiler on top of it. While I'm adding a tiny little bit of typing to it these days, it's only to distinguish "must be a Ruby object" from "can be anything".
You can get away with no type information for surprisingly much. The main hassle is dealing with layout of structured data, but even then it's relatively straight-forward to deal with through a combination of memory and documentation (but maybe it's the assembly programmer in me - my first compiler was written in m68k assembly and then gradually translated into inline assembly in the language the compiler was for)
That core is not by any means a fully fledged usable language, though, which BCPL of course was/is. Martin Richards, the creator of BCPL even still has a web page for it that includes a BCPL distribution [2] with both examples and the compiler.
[1] http://www.hokstad.com/compiler [2] http://www.cl.cam.ac.uk/~mr10/BCPL.html