5 ms·
> The problems it was well designed for have disappeared I think C is still an incredibly relevant language. There are still plenty of cases where it's useful
by skohan 7y ago
> The problems it was well designed for have disappeared
I think C is still an incredibly relevant language. There are still plenty of cases where it's useful to have a very simple, un-opinionated language for working close to the metal. I think C as "portable assembly" is still incredibly useful, and no other language has really filled that slot perfectly.
> C has bad memory management because it was built when programmers had kilo- to mega- bytes to play with and needed perfect control.
I don't think C's memory management is bad. It's not right for heaps of problems where it's not needed; for example for things like front-end work, or server software where the main concern is stability, manual memory management is unnecessary. But for domains like computer graphics, or for optimizing compute-bound workloads, manual memory management is still completely relevant.
To me, the parts of C which seem a bit dated are the lack of some basic "quality of life" features we take for granted in most languages. For instance, I would be happy with a language almost exactly like C, but with a slightly more powerful type system first-class optionals, and some syntactic sugar for dealing with arrays (i.e. counts, map/reduce/filter functions etc.)
- makapuf 7y agoI think that manu of C issues come from the APIs rather than the language. You could do safe memory management by only using refcounts in the api and sticking to it. You could have bound checking in the strings library. But strings are 0 ended (more an API design since strings are not in C). Not saying that its bad design because it allows >256 length strings with only one byte of overhead. But it is a compromise that made sense but has its drawbacks. There are a few stdlib complements in C (strlcpy, antirez sds lib for strings) but it's a shame a more modern lib/runtime has not been established as a standard while keeping C strengths. Or maybe I'm ignorant.
- gatherhunterer 7y ago> I don't think C's memory management is bad. It's not right for heaps of problems Pun intended?
- Leherenn 7y agoHave a look at Zig. That's what it's trying to achieve.
- skohan 7y agoThanks, I will check it out.
- annowiki 7y agoI think you're right. I'm by no measure a C programmer, but I've always regarded it as something that people don't like coding in because it's difficult, not because it's a bad language. Most people complaining about C are like guitar players complaining about the piano. It's more complex, but it has to be given its role. That said, the fact that K&R didn't specify the size of an int or long complicated matters, but it seems to be an accident of history, not a mistake in design. They had no choice.
- P_I_Staker 7y agoI'm a C programmer. I don't know if I'd say it's a bad language, but I definitely hate it. I agree wholeheartedly with OP about the quality of life stuff. I'm constantly amazed by what C will let you do. The footguns and lack of type checking. C compilers will link a function to a variable for instance. Don't forward declare your functions, and you might not even get a warning (yes some compilers don't give warnings by default for implicit functions). The linker will then go to the symbol table find anything that matches and place a function call. That's just one example, but they're many. C builds erroneous code.
- YSFEJ4SWJUVU6 7y ago>yes some compilers don't give warnings by default for implicit functions Broken or ancient compilers. That's as much C's fault as it's Intel's fault that Windows 10 doesn't run on Pentium MMX. Implicit functions are not part of C; they were gotten rid of back in 1999!
- P_I_Staker 7y agoI agree to some extent (I'd also add that undisciplined and apathetic programmers are an even bigger problem). I have to disagree about implicit functions not being a part of C anymore. I've yet to see one generate an error; this is optional, and frequently not used. I'm including brand new, state of the art compilers, even (default) gcc. Of course, not even emitting a warning is bananas. I confirmed this, with the following snippet: // start fail.c int fail = 0; // end fail.c int main(void) { fail(); return 0; } gcc --std=c99 -g main.c fail.c -o main.exe && gdb main.exe -ex run # Cmd line junk, however a warning was emitted for implicit function "fail" Program received signal SIGSEGV, Segmentation fault. 0x00407020 in fail ()
- acomjean 7y agoC will remain relevant because Linux is written in C. Accessing all the core functionality of the os (networking, files, ipc...) requires using C libraries the os provides.
- seamyb88 7y agoEven stronger than that - C will remain relevant because Linux (or OS in general) MUST be written in C (or assembly, but good luck with that). C's flaw: memory can fail. C's (necessary) advantage for writing an OS: memory can fail.
- ptr 7y agoThis is quite easy to refute: https://www.redox-os.org/ https://www.redox-os.org/ http://menuetos.net/ http://menuetos.net/ And what does “memory can fail” mean? Cosmic rays? Those aren’t really good for anything afaik.
- ben-schaaf 7y agoUsing libc isn't a strong requirement. There's nothing stopping you from making your own syscalls for everything in the language of your choice. I recon C remains relevant because replacing what's already been written in it is a lot of work for very little benefit.
- zucker42 7y agoI don't think C is un-opinioniated. It's opinions are just quite popular, so people don't think they are opinions.
- skohan 7y agoI mean, there are always matters of degree. Sure C imposes some structure by nature of it's syntactic choices, but it's extremely wide-open when compared to other programming languages. Lisp, for example, is very opinionated when it comes to things like side-effects. Go is opinionated when it comes to how memory should be managed. Rust is opinionated about when data should be readable and writable, and passed between threads. C doesn't impose any of these restrictions, largely by virtue of being low-level, and moreover, it should be possible to implement whatever data transforms are implemented in any of those other languages in C as well. The inverse is not the case, so I would argue that C is more permissive than any of those languages.
- robto 7y agoIs Lisp opinionated about side-effects? Maybe Clojure is, but have you looked at Common Lisp or Emacs? I can't think of a less-opinionated-about-side-effects application than Emacs.
- kazinator 7y agoLisp is opinionated about side effects like this. * In the absence of language extensions, you don't have a pointer type that can be incremented all over the place and dereferenced. You don't just mutate memory willy nilly. * In relation to the above point, (in the absence of a language extension like "locatives") there is no address-of operator; we can't pass the address of a variable somewhere to have it changed. This can be simulated with a lexical closure, whereby we provide the function to do perform the change, which is called from somewhere. "Use lexical closures as thunks if you want var parameters" is quite opinionated. * All mutation takes place through data-structure-specific functions (like rplaca for mutating the car of a cons cell), or dedicated special forms (like setq for mutating a variable). The use of generalized places like (incf (car x)) compiles into type-safe function calls. On one particular Lisp, CLISP, that looks like: 1> (macroexpand '(incf (car x))) (LET* ((#:TEMP-3341 X) (#:NEW-3340 (+ (CAR #:TEMP-3341) 1))) (SYSTEM::%RPLACA #:TEMP-3341 #:NEW-3340)) there is no idea there of calculating some effective address and just clobbering bits through that pointer. The original value is accessed using car, and the mutation happens opaquely inside the SYSTEM::%RPLACA function. That could be inlined by the compiler, but the model is basically that mutation of objects is done via an API. * The argument evaluation order of standard functions is well-defined, so side effects occurring in argument forms are well sequenced: (let ((x 0)) (list (incf x) (incf x) (incf x))) --> (1 2 3) ;; required result in ANSI Lisp (Scheme bungles this by having less of an opinion; it has C-like unspecified argument eval order.)
- boomlinde 7y agoI've always argued against the idea that "portable assembly" is a useful way to look at C. It is terrible for the purpose in the sense that the compiler is allowed to generate code that has little to do with what you wrote in terms of procedure. Assembly on the other hand is useful exactly because it affords minute control of procedure. In my view, C is a secretly declarative language where your program is a declaration of constraints for the optimizing back-end that just happens to look a lot like procedural code. I can write what looks like function containing a loop or a memory write and call it from main only to end up with a program that only loads a constant in a register and returns. Because of this and the sometimes complex conditions that enable some optimizations, it's hard to argue about C code in terms of its performance without falling back on analyzing the actual "non-portable" assembler output of the compiler.