3 ms·
> I think C is more difficult that it should be I think if you view C as a cross-platform macro assembler it makes more sense. You can read the origin story of
by gregjor 2y ago
> I think C is more difficult that it should be
I think if you view C as a cross-platform macro assembler it makes more sense. You can read the origin story of the C language. The main author or inventor of C, Dennis Ritchie, intended to make a language that targeted the capabilities of hardware available at the time (circa 1972). The goal was to write a reasonably high-level language that did not create significant performance issues compared to assembly language or other languages available at the time. If you go back to that era (my career started in the late '70s) every computer manufacturer had their own instruction set architecture (ISA) and their own proprietary languages and tools (frequently variants of FORTRAN, COBOL, etc.). To make a cross-platform operating system (what we now know as Unix) the team needed a cross-platform language that could express what the hardware of the day could do. C models how almost all digital computers work at a low level, but not as low as the architecture-dependent assembly language.
The authors of C and Unix did optimize the language and OS and associated tools, but they optimized them for the available hardware, out of necessity. They did not optimize for programmers who didn't know assembly language or struggled to understand pointers.
C has remained relevant in part because of what you call inertia -- huge amounts of code already written. The language has evolved and changed over time, but not much, because the underlying principles of digital computers that C models have not changed much.
> As you probably know, to pass a function as an parameter in C you have to use function pointers
Yes. C does not have first-class functions. It doesn't have first-class strings or arrays either. C has primitive data types -- char, int, float, pointer -- that correspond directly to the kinds of things CPUs work with. Again the author of C did not set out to make a general-purpose language for application programmers like us. Languages with first-class functions already existed at the time (Lisp predates C by almost two decades). Functions don't exist at the assembly language level, so while C has functions it does not let you pass them around other than with pointers -- the same way it lets you pass "strings" around.
Of course anyone used to using a language like Python or Javascript, which do not intend to model CPUs in a way that minimizes performance cost, will find C frustrating because it leaves it to the programmer to do things like get a pointer to a function and put it into an array. Many modern languages have syntactic sugar so we can pass functions around, which makes C look primitive and clunky by comparison.
> I don't see a world where this is the optimal way of doing things
I tried to describe that world. You can look at it a couple of ways. C comes close to optimally modeling ISAs, which rely heavily on indirection (pointers) and a small number of primitive data types. Other languages from the same era did that less optimally and we've mostly forgotten them. C also gives programmers just enough expressive power to write code that directly translates to assembly language but hides a large amount of CPU ISA-specific details.
Compare how C passes an array of function pointers to trying to do the same thing from Python (to a C API). You probably have some helper functions that can handle the significant mismatch between Python data types and functions (in an interpreted language) to C functions, but if you had to roll that yourself it would look a lot more baroque and fragile than the C version.
C abstracts CPU instruction set architectures just enough to make programming an order of magnitude easier without imposing a big penalty. Python, Javascript, and many other higher-level languages abstract and wrap C code to make programming easier as well, but impose significant performance penalties. Sometimes we don't care about or can live with those penalties, sometimes we can't, as in the problem you described in the original post.
- megaloblasto 2y agoI tried to describe that world. I think you've done a very good job of explaining that world. Perhaps I was originally misdirecting my frustration at C, and it should have been at the fact that I am trying to solve such a computationally intensive problem that I cannot afford to incur the performance penalty caused by the abstractions in languages like Python. This really helped me understand the use of C, thank you very much. I wonder if one day soon computers will be powerful enough, and compilers optimized enough, so that even our biggest scientific simulations can be written in highly abstract programing languages. I have a feeling that we will still be wanting to harness every little bit of computational power we can for a long time to come, and low level languages like C and Rust will maintain their necessity. Thanks again.
- gregjor 2y agoGlad to have a useful exchange on HN. The difference between C and Python comes down to layers of abstraction and conveniences for the programmer. Those abstractions and conveniences come at a cost measured in performance, another way to say demands on the hardware. Computer hardware along with compiler and related technology has come a long way since C got introduced, but of course C benefits from those improvements so it remains relatively fast compared to more abstracted languages such as Python. Writing C also demands more low-level knowledge from the programmer than writing in Python or Javascript, which limits C's accessibility to programmers who just have a job to do. Right now many people expect or hope that AI in the form of LLMs will let us generate efficient code from human-language descriptions, eliminating the need for expert C programmers to write and optimize code "by hand." I don't share those expectations, I see mostly hype and a lot of work trying to get AI to mimic a human programmer (e.g. writing Python code rather than giving optimal solutions to problems). My decades in the software business have perhaps made me jaded and cynical -- I have heard grandiose claims about revolutions in programming before. But you never know, maybe someone (or some AI) will figure out how to bridge the gap between requirements imperfectly expressed by people and what digital computers can efficiently do.