neocity/language-criticism/c.jade

76 lines
4.2 KiB
Plaintext

extends ../templates/main.jade
block title
| C | Language Criticism | xigoi
block content
h1 C Language Criticism
p.disclaimer I know that C was designed a long time ago when there wasn't much knowledge about language design. I'm not trying to berate its original creators, I just think it's time to move on to more modern systems programming languages like Nim, Rust or Zig. That's why this criticism is from a modern perspective.
p.notice I found
a(href="https://eev.ee/blog/2016/12/01/lets-stop-copying-c/") this article
| which explains many things much better than I, so please check it out. My article contains a few duplicates and some additional points.
h2 Preprocessor
p What's a better way of doing imports and macros than embedding another language with completely different syntax, which does naive text substitution, into your language? In order to avoid dangers which are not present in any sane import/macro systems, you have to do ugly hacks such as:
ul
li
p Include guards
pre
code.
#ifndef YOU_NEED_TO_MANUALLY_MAKE_SURE_THAT_YOUR_FILE_ISNT_INCLUDED_MULTIPLE_TIMES
#define YOU_NEED_TO_MANUALLY_MAKE_SURE_THAT_YOUR_FILE_ISNT_INCLUDED_MULTIPLE_TIMES
// your code here
#endif
li
p The
code do { ... } while (0)
| thing to make sure that a macro can be used as a normal function
li
p Wrapping everything in parentheses to make a macro work like a normal function
pre
code.
#define MAX(a, b) ((a) > (b) ? (a) : (b))
p If any parentheses are left out, it results in counter-intuitive behavior. Actually, even with them it doesn't work like a normal function: the arguments will be evaluated as many times as they're in the macro body!
h2 Braces & Semicolons
p See
a(href='braces-semicolons.html') Braces & Semicolons
h2 Syntax inconsistencies & warts
p Since many other languages (Java, C#, JavaScript, ...) have mindlessly copied most syntax from C, these mistakes have a profound effect on a whole family of languages.
ul
li All control structures that take a statement (if, while, for, switch) have the form of
code KEYWORD (SOMETHING) STATEMENT
| . Except for the do-while loop, which for some reason has the form
code KEYWORD STATEMENT KEYWORD (SOMETHING);
| . Totally different and including an extra semicolon.
ul.qa
li But it visually indicates that the condition is first checked after the statement!
li Then why is a for loop written as
code for (INIT; CONDITION; STEP) STATEMENT
| rather than
code for (INIT; CONDITION) STATEMENT (STEP);
| ? By the same logic, we should visually indicate that the step (usually increment) is first executed after the statement.
li The choice to require an if/while condition to be wrapped in parentheses, rather than requiring the body to be wrapped in braces (as in Rust). Not only does this introduce syntactic noise, but it leads to subtle bugs if you mess up indentation:
pre
code.
if (launch_button_pressed)
check(missile); /* this was added in after we decided to make our missile system safer */
launch(missile);
li The for loop is just another way to write a while loop, instead of something actually useful like Python's
code for item in items:
| .
li The syntax for labels (including switch cases) is completely different from everything else. For consistency, it could be something like
code label (NAME) STATEMENT
| and
code case (VALUE) STATEMENT
| .
h2 Tooling
ul
li By default, the compilers don't have most warnings enabled. And it's very difficult to actually enable all warnings.
code -Wall
| enables only some warnings. What the fuck?
li The default name for the compiled executable is
code a.out
| , instead of being based on the source filename. So you need to do things like
code gcc my_awesome_program.c -o my_awesome_program
| .
li You need to specify the libraries you're using in the compilation command, instead of just putting them in the source file.