The core of what makes C elegant is that basically everything that looks atomic is atomic, in the sense of taking O(1) space and memory (at least until C99 introduced its abominable variable-length arrays, and perhaps some other features I'm forgetting about).
Absent macro obfuscation, it is easy to reason about what a snippet of C does and how it translates down to machine code, even taken out of context. In C++, something as innocent as "i++;" could allocate heap memory and do file I/O.
The downside is that C code can become quite verbose, and to do anything useful, it takes a lot of ground work to basically set up your own DSL of utility functions and data structures. For certain applications, this is an acceptable tradeoff and gives a great deal of flexibility. I think teaching this bottom-up approach to programming can be quite useful - in a way, it mirrors the SICP approach, albeit from a rather different angle.
The question is, why are there not more languages that have the same paradigm, but also add basic memory safety, avoid spurious undefined behavior, provide namespaces, with a non-stupid standard library, etc.?
"The question is, why are there not more languages that have the same paradigm, but also add basic memory safety, avoid spurious undefined behavior, provide namespaces, with a non-stupid standard library, etc.?"
...basically just described Modula-3. It meets your requirements, was easy to read, had concurrency, had decent stdlib which had some formal verification, and could act as low-level as you needed with "UNSAFE" keyword. Brilliant design given all tradeoffs it balanced. It had some commercial uptake and was used in CVSup for FreeBSD.
Note: Important to not ignore it once you see "garbage collection." The GC was optional with a single keyword determining whether you or it handles a specific variable. Let's one pick and choose their battles with fate. :)
Note 2: The Obliq distributed programming language was an interesting project based on Modula-3. The SPIN OS, written in Modula-3, let you link code into a running kernel in a type-safe and memory-safe way for reducing context switches for performance.
Much of the code in the fantastic C Interfaces and Implementations [0] is inspired by Modula-3. It's a fantastic book to work through after finishing K&R for anyone wanting to learn how to write safe and reusable C code.
(Regular HN readers will recognize the author of the top review on Amazon.)
Wow. Interesting to see the two converge that way. That's the glowing review I've seen of a book in a while. Guess I'm going to have to get it just in case. :)
> The question is, why are there not more languages that have the same paradigm, but also add basic memory safety, avoid spurious undefined behavior, provide namespaces, with a non-stupid standard library, etc.?
You mean Algol, NEWP, Mesa, PL/I, PL/M, Modula-2, Ada and similar?
This is why I made a BASIC-like language with 4GL-style utility functions that extracted to C. I knew effects of each one. BASIC didn't have C's issues and compiled pretty directly. Compiled fast, too.
Not recommending this route today as I just happened to start with BASIC. More like combining a simple, easy-to-compile, safe-by-default language w/out GC and with macros that extracts to portable C. Should make programming in C easier while providing all the benefits of C as my system did.
I've been eyeballing Nim language for this since HN commenters pointed out it's close to the goal already:
Someone might even be using a subset of it as a high-level C language. I'd be interested to know if anyone reading is doing something like that. Plus any other language besides Nim that can closely map and extract to C without its issues.
Absent macro obfuscation, it is easy to reason about what a snippet of C does and how it translates down to machine code, even taken out of context. In C++, something as innocent as "i++;" could allocate heap memory and do file I/O.
The downside is that C code can become quite verbose, and to do anything useful, it takes a lot of ground work to basically set up your own DSL of utility functions and data structures. For certain applications, this is an acceptable tradeoff and gives a great deal of flexibility. I think teaching this bottom-up approach to programming can be quite useful - in a way, it mirrors the SICP approach, albeit from a rather different angle.
The question is, why are there not more languages that have the same paradigm, but also add basic memory safety, avoid spurious undefined behavior, provide namespaces, with a non-stupid standard library, etc.?