Hacker News new | past | comments | ask | show | jobs | submit login
The Ten Commandments for C Programmers (1987) (liu.se)
241 points by ingve on May 23, 2020 | hide | past | favorite | 128 comments



This should probably carry a date stamp; my guess would be that it dates from 1990 or so.

Most of the advice is still good, but I would object to (3):

* Excessive casting can be a problem in itself, as it hides genuine type errors (e.g. you think you're casting an int to long, but in reality the variable is a pointer)

* Casting NULL is pointless, as it's already defined by the standard to be a pointer constant, compatible with all data pointers.

* Much of the language about "prototypes" (a.k.a. standard C) was justified at the time, but no longer reflects reality nowadays. It would have to be a very exotic platform that still uses a pre-ANSI C compiler.


Dated? #10 is from a 1980's MOTD message of the day: All the world's a VAX, And all the coders merely butchers; They have their exits and their entrails; And one int in his time plays many widths, His sizeof being N bytes. At first the infant, Mewling and puking in the Regent's arms. And then the whining schoolboy, with his Sun, And shining morning face, creeping like slug Unwillingly to school. -- A Very Annoyed PDP-11


Heh. Getting a response from you must be peak 1990 ;-)

By the time I got started on Usenet "All the world's a VAX" was only in use as a proverbial misconception anymore. At the time, all the world was a Sun Workstation.


Yep, circa 1990, a SPARCstation or Sun-3 running SunOS 4 seemed the place to be, for having most software off the 'net build easily.

I also worked on almost all the other engineering workstation platforms, for porting purposes, but a SPARCstation was my preferred main workstation, overall.

(I was a kid who stumbled upon a dream job. So many expensive toys, so much I could learn, and this cool Internet thing...)


I bought a Sparc 5 back in 1996 or so, from a company going out of business. I felt like a king. Nobody had stuff like that at home back then.


Wow... just seeing a post of Cliff Stoll is incredible. I love that TV movie and the book.


>* Casting NULL is pointless, as it's already defined by the standard to be a pointer constant, compatible with all data pointers.

You should still cast NULL when passed as an unnamed argument to a variadic function. While NULL is defined to be a null pointer constant, that doesn't mean it has a pointer type (all integer literals with a value of zero are null pointer constants in C, but they have an integer type).

(Strictly speaking, all unnamed pointer arguments to variadic functions should be converted to a compatible pointer type that the variadic function expects. For example, the printf-line of functions expect a pointer-to-void argument for a conversion specifier %p. If you pass a pointer-to-int instead, technically the behaviour is undefined.)

(To whom it may concern: I would appreciate at least a rebuttal. It's not like this is a subjective matter.)


It's unfortunate that you're getting downvoted; there's for sure real dragons at the intersection of the NULL literal and variadic functions since it's totally legal for NULL to be defined as such:

  #define NULL 0


Much, much more subtly nasty, it's also legal for NULL to be defined as:

  #define NULL ((void*)0)
and then passed to a function that expects variadic int* parameters on a machine where register-sized addresses are word-aligned and thus int* has a different sizeof (and/or bit-level representation) than void*.


You're right, I was misinterpreting the language of the standard.

As a practical matter, C implementations typically define NULL as a void pointer, so the cast is not necessary in those implementations (In C++ pre C++11, NULL is always defined as a literal 0, so the cast is definitely necessary).

But it appears the standard allows C implementations to define NULL as a literal 0 or as 0L as well, so the cast is needed in portable code.


> If you pass a pointer-to-int instead, technically the behaviour is undefined.

But if you cast the intptr to voidptr, the behavior is defined, right? (Besides that %p is nonstandard iirc)


Yes. Also, %p isn't non-standard, however the conversion is implementation-defined.

(The reason why I used the word technically earlier was because on all common platforms int-pointers and void-pointers – and indeed all object pointers – have identical binary representation.)


    Subject: Ten Commandments For C Programmers
    Message-ID: <8771@utzoo.UUCP>
    Date: Wed, 14-Oct-87 17:35:26 EDT

    Subject: The Ten Commandments for C Programmers (Annotated Edition)
    Message-ID: <1990Nov4.021618.24681@zoo.toronto.edu>
    Date: 4 Nov 90 02:16:18 GMT


1990, University of Toronto Zoology... one could make a make a good guess at the poster: https://en.wikipedia.org/wiki/Henry_Spencer :)



> It would have to be a very exotic platform that still uses a pre-ANSI C compiler.

Not "exotic" so much, really. Obviously those days are long behind us now, but for many years the very last refuge of K&R C was the bootstrap compiler for gcc.

By the 90's, for revenue and product differentiation reasons all the big Unix vendors had moved their optimizing toolchains into their "developer" software packages and out of the base system. But for legacy compatibility reasons they still needed a working K&R C compiler in /bin/cc.

So for almost two decades, the only contact working engineers had with pre-ANSI compilers was using them to bootstrap a real compiler (gcc) on their new, fancy, high performance, very mainstream and non-exotic workstations.


This! Casting the output of a function that returns (void*) is usually the first red flag of code not written by an experienced C programmer.


it can also just indicate that when it was written it also had to compile as C++ for whatever reason.


That's an even redder flat. Why would you even want or need that? I understand that sometimes it is convenient to write header files that can be read likewise by C and C++ compilers. But why would you ever need a piece of code to be compiled into an object by either C or C++ compiler, indistinctly?


That was essentially Microsoft's advice because they didn't want to keep their C compiler uptodate:

"We recommend that C developers use the C++ compiler to compile C code (using /TP if the file is named something.c). This is the best choice for using Visual C++ to compile C code."

From: https://herbsutter.com/2012/05/03/reader-qa-what-about-vc-an...


I'm going to abstain from commenting on this topic. I am not emotionally prepared.


There are several reasons why people would do this, but the decision is often not made by the person writing the code, so it may be a red flag to you, but it doesn't point to inexperience of the author.

In addition to the MSVC issue mentioned in the sibling comment, I've worked on projects that used clang thread safety analysis, which at the time (and maybe still today) was only available for C++, so the build for that analysis was configured to build all C source files as C++.


What can you do with a void pointer without casting it, apart from comparing it to NULL?


You can (implicitly) convert it to another pointer type, e.g.

    int *buf = malloc(sizeof(*buf));
(It's noteworthy that while there's an implicit conversion above, there's no such thing as an implicit cast.)


This is a pretty well-regarded answer, with motivation for why you should not cast [1].

Of course it's not something everyone agrees to, but at least a lot of people seem to.

[1] https://stackoverflow.com/questions/605845/do-i-cast-the-res...


Interesting. Not casting a void pointer return value seems like a bit of a shibboleth for the "C is not a subset of C++" community.


A "better" shibboleth is using "new" and "old" as identifiers. It serves as a good barrier to avoid accidental C++ compilation.


Generic data structures work great if they use a void* since malloc returns a void*. Just malloc your structs, and suddenly a single set of 10 or so functions can work with all data types to build queues, lists, hash maps, etc


You can compare it for (in)equality to another void pointer.


You can assign it to any data pointer variable, and you can printf("%p") it, for example.


I dislike implicit type conversions, but I think every cast needs to be accompanied by an assertion. Just sprinkling casts everywhere does nothing but silence important compiler warnings.


>> I dislike implicit type conversions...

What do you think of "auto" in C++ ?


Not the parent, but `auto` in c++ improves the situation wrt implicit conversions as variables now automatically get the type of the thing assigned to them. IOW: less unintentional implicit conversions.


'auto' is only available to use when the type of a variable can be automatically deduced from its initializer, meaning the declaration would be redundant. It has nothing to do with type conversions.

edit: now I see what you mean in the context of adding assertions to make type conversions safer, and how there could be some parallels with auto for that


It's an example of making something explicit implicit.

Whatever the answer, it won't surface a contradiction; but that doesn't mean it's not an interesting, obliquely related question.


It's implicit declaration, which seems worse in some ways than implicit conversions. After a conversion you know what type you have even if not the type you started with.


> prototypes

The following C code compiles today without complaint on gcc:

    foo(i, j) { return i + j; }


An interesting thing about the old system is that it could have checked data types just fine. This would have required linker support, but in the early years C didn't have the influence to make that happen. It would have been the tail wagging the dog. Linkers were designed for other languages, then used by C.

With linker support, C++ would never have had to resort to name mangling.

The foo(i,j) in your example could have caused the compiler to emit assembly directives to specify the argument types and return type. The assembler could have put these into the object file. The linker could have checked for compatibility when linking. The linker could have produced warnings, errors, or in some cases even thunks.


Yes, I did not mean to imply that old-style code no longer compiles today, but that support for prototypes is near-universal nowadays.


From the following passage, I would have thought this would have been written as recently as today.

> As a lamentable side issue, there has been some unrest from the fanatics of the Pronoun Gestapo over the use of the word ``man'' in this Commandment, for they believe that great efforts and loud shouting devoted to the ritual purification of the language will somehow redound to the benefit of the downtrodden (whose real and grievous woes tendeth to get lost amidst all that thunder and fury). When preaching the gospel to the narrow of mind and short of temper, the word ``creature'' may be substituted as a suitable pseudoBiblical term free of the taint of Political Incorrectness.


I would add "Never cast malloc" to that as well. It's pointless and only required if you're writing C++, which is not C.


> if thou thinkest ``it cannot happen to me'', the gods shall surely punish thee for thy arrogance

This one is a universal experience. :)


Hmhrhm... If thou aren't abide by them, my wrath follows, and make it go BAM!

edit: ...my wrath follows, and it shall go BAM!


#3 sounds extremely obsolete. I don't completely understand what they mean, but perhaps they are thinking pre-C89, when it wasn't as common to list the args in function declarations, so the compiler could not always correctly convert the type?

I remember in the 90s some libraries (like X11 headers) would put the types of function arguments inside an ifdef to be able to compile in some archaic place.

Edit: or maybe they are thinking of varargs. This could still be an issue with printf today.


I get why they are using King James language but a button to translate to modern English would help.


It's not even correct - "thy arrogance" should be "thine arrogance"


when thou least expect it.

Should be “when thou expectest it least”

lest thou tear thy hair

Should be “lest thou tearest thine hair” as I seem to recall the h sound acting like vowel for words that sound different based on what follow them.

lest grievous harm befall thy program.

Should be “befalleth”


Too bad you can't "requesteth a pull" to update the language a bit.


I believe "-eth" is a 3rd person ending (he/she/it), e.g. If thy header files fail should be "faileth".

"The third person sing. Present, ending in th, as taketh, bringeth &c. is now confined to sermons and grave discourse." - John Hunter, Text-book of English Grammar 1848

My favourite -eth, from the start of Moonlighting's Atomic Shakespeare episode:

Good morrow, sir. I'm Lucentio, come hither for to see fair Padua, pleasant garden of great Italy, to seek out and happily begin a course of learning and studies herein.

You've mistaken me, sir, for someone who careth.

https://youtu.be/ijUr6p8xSBM?t=140


I, for one, prefer my bibles with interspersed lines of Ancient Greek, so that you can interpret yourself. Our language will never keep changing, but the source remains the same.


The Ten Commandments were originally written in ancient Hebrew. They were passages in the Hebrew Bible, which the Christians later adopted as the Old Testament. It was the New Testament that was originally written in Greek.



The C++ "equivalent" of this are the "C++ Core Guidelines", which, like the language itself, are a couple of orders of magnitude larger:

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppC...


"If thy header files fail to declare the return types of thy library functions, thou shalt declare them thyself with the most meticulous care, lest grievous harm befall thy program.

The prophet Ansi, in her wisdom, hath added that thou shouldst also scourge thy Suppliers, and demand on pain of excommunication that they produce header files that declare their library functions. For truly, only they know the precise form of the incantation appropriate to invoking their magic in the optimal way."

This commendment made me afraid of the dark. Was it common in those days to have to guess to calling convention of libfunctions?



I'd supplement the first commandment with "Fear not the -Wall, for it clears thou path to truth".

Personal reminder: "Initialize thou variables or endure the torturous trials of doubtful debugging"

"Never refuse the helping hand of thou compiler" and "No one seeking a refuge after arduous truth seeking journey in C has been turned away from StackOverflow."


Thou shalt not follow the NULL pointer should probably be appended with and thou shalt not map the zero page.


Kind of hard when the operating system does it for you... https://groups.google.com/d/msg/comp.unix.aix/0dv4N0qmgVQ/ty...


OSX (well, OSX ld, not OSX itself) actually does this for you and unmaps the entire low 4GB for good measure, giving new meaning to 32-bit clean.


Sometimes, the zero page is available to your C program. For example, your C code could be part of the Linux kernel's boot code, or could be running on embedded hardware.


NULL is not the zero page... well at least in the C machine. NULL is NULL. But then again, it does work on systems where it matters(e.g. address 0 is valid and needed)


11. Thou shalt try C++ or Rust


I come from low-latency java world (yes, that is a thing) and to be effective in my line of work I had to get a decent understanding of what the OS (linux) does under the hood.

Learning C was a blast and I really enjoy reading and writing C code and studying kernel sources.

C++ on the other hand is a fully matured abomination and I want nothing to do with it. Now you can down-vote me into oblivion.


Indeed, C is a much much simpler language. C++ is a language which can take you a good 10 years to master (and while you do so, your knowledge becomes partly outdated)...

On the other hand, you enjoy your C until you find yourself:

* In macro hell to get something complex done

* With overly long functions and function name prefixes.

* Needing to write something serious and big - requiring libraries of all sorts, and noticing they mostly don't exist.

* Wanting to tell the compiler optimizer things that C can't tell it.

* Needing to compute some things at compile-time.

... and then you start developing a taste for the "abomination".


* In macro hell to get something complex done

IMO, macro hell is something you bring upon yourself. I rarely felt the need to abuse the preprocessor in awful ways in order to build something.

* With overly long functions and function name prefixes.

I'm puzzled how you can get in such a situation. Running out of function namespace? How?

* Needing to write something serious and big - requiring libraries of all sorts, and noticing they mostly don't exist.

There are plenty serious and big projects in C and there are _plenty_ of libraries. Also, C++ can be linked with C, so... I fail to see how you don't get the same kind of issues with C++ if there are any.

* Wanting to tell the compiler optimizer things that C can't tell it.

This might be indeed a problem, but... what can you tell it using C++ to the compiler optimizer? I'm not really a C++ guy so, really, do you have more options? I know there are compiler specific pragmas an modifiers in C as well, but does C++ have specific C++ language stuff and not C++ compiler stuff it can set?

* Needing to compute some things at compile-time.

Again... what yould those things be? CRC's? You can do that in C if the compiler allows you as well (gcc and clang do). What else? And what more exactly does C++ bring to the table concerning this?

Honestly, I have to think reaaaal long an hard about things that the C lang doesn't let you do or constrains you. It's one of the most liberating languages, honestly. I work with it day in and day out, so I might be biased, say what you want about C, but not that it's not powerful!


> what can you tell it using C++ to the compiler optimizer? I'm not really a C++ guy so, really, do you have more options?

Yes, in several ways, including:

* Move semantics - you can make the compiler aware that some values are "going away" soon and can be cannibalized rather than conserved. * Compile-time execution - a significant (and growing) subset of the language can simply be computed at compile-time rather than run-time. So if you have a certain function which computes something - anything that doesn't involve I/O (and until C++20 - uses a fixed amount of memory), and your inputs are known in advance, the function won't have to run whenever you run the program, but would be removed entirely in favor of the result.

To see how these and other language features combine to allow for highly-efficient code, check out this video:

CppCon 2016: Jason Turner “Rich Code for Tiny Computers: A Simple Commodore 64 Game in C++17” https://www.youtube.com/watch?v=zBkNBP00wJE

Where you write an implementation of the Pong game - with high-level, straightforward code, and no "dirty tricks" - whose compilation result requires exactly 0 stack and 0 heap space.


Some of that capability is there only to overcome optimization problems that were created by C++ features. You don't need to make the compiler aware that some values are "going away" soon if that is clearly obvious. Without layer upon layer of object obfuscation, optimization is a much easier problem.

In C too, functions are removed entirely in favor of the results. This is a quality-of-implementation issue. There are good and bad compilers for most languages. C is less dependent on compiler quality however, with relatively simple compilers being able to produce good output for stylistically typical code.


I really love C, although I'm no expert by any means. C++ and Rust (and D) are different kinds of languages, they have many many more features. There isn't an adequate replacement yet. Aside from having GC, if anyone mentions Go, yes the syntax is simple but the runtime is a massive magic black box, I don't like magic. The closest things that I can see are Zig or the yet unknown language that Drew Devault is working on[0]. So people know about Zig of course, but the reason I mention about Drew's language that he has hinted at with snippets is that I can see by his posts that he both loves and respects C and he cares about complexity[1], I really really look forward to seeing what he's been up to.

[0]. https://drewdevault.com/2020/04/15/Status-update.html [1]. https://drewdevault.com/2020/01/04/Slow.html


> There isn't an adequate replacement yet.

D as Better C works very well as a replacement. I've converted a lot of code from old C to BetterC and it goes very quickly (once you remove the use of the preprocessor, which can be tricky if you use the preprocessor as a metaprogramming tool). The syntax is nearly identical.

https://dlang.org/blog/2017/08/23/d-as-a-better-c/

Note that no D runtime library is required. Just the C Standard Library.

(Yes, I am in charge of the D Language Foundation. No, I don't receive a nickel from it. I do it because I believe in it.)


Actually yes I did forget about BetterC and it has been on my radar for a while. I have played with D before and honestly out of all the options in this space I've found it's probably the one I would go for on a project. It seems to strike the best balance between productivity and performance for me, the runtime seems much less magical than Go. I will definitely check out BetterC!


The biggest feature of C is its ABI stability guarantees. Swift is one of the few languages that has tried to retain that.


How does C provide ABI stability? If I send someone .o and .a files, I don’t think they can just use them in the general case.


C does not provide ABI stability itself as a language, however the language does make it easier for libraries (including specific implementations of the standard library) to provide ABI stability.

Rust does not provide the facilities to write libraries with stable ABIs, and C++ libraries have to be written carefully to achieve ABI stability. More precisely, important C++ and Rust language features (templates and generics, respectively) conflict with the ability of providing ABI stability (at least it was thought so... Swift is novel in how it provides ABI stability guarantees for library writers alongside generics).


I wonder if anyone's ever tried something like "C with slices, destructors, and copy/move semantics".


Of course. Just use C++ and set some linter rules to enforce disabling other C++ features.


That plus "avoid pure virtual classes", "no use of the heap", "C standard library and header-only libraries only", "compile with no exceptions" gets you close to embedded C++. Except also with classes.


Is this something you would recommend to newcommers? I wouldn't. I can agree that on technical level such subset has a decent set of features and gets the job done. On the other hand when learning how to use this subset, you'll still come across stack overflow answers and other C++ materials that will contradict such methodology, and other coworkers will occasionally challenge that particular stack of choices with their own favourite C++ features. You still have to learn how exceptions work and why avoid them, what is heap and how to disable it, what are pure virtual classes and so on.

I dislike the argument that C++ is great because you can limit yourself to appropriate subset. It becomes a different thing while still being called C++, which is miscommunication. If you can brand your subset as EmbeddedC++ and gain widespread audience, then we're closer to good thing. (except there's lot of embedded happening on Linux boards where "normal" C++ is acceptable)

My frustration mostly comes from working on huge embedded C++ project where each separate corner of codebase used its own subset of language. This brings down complexity and reduces mental overhead locally, but reasoning about the whole system is impossible.


I would much rather recommend something like "C with bounds-checked arrays" than a form of "standard" C++ to newcomers. Yes, StackOverflow will not help much, but I think avoiding the huge amount of features that the rest of C++ brings is well worth it. You are probably not advocating for dumping everything at once onto a beginner, so why not pick a subset that is both really small and gets you quite far?

> You still have to learn how exceptions work and why avoid them, what is heap and how to disable it, what are pure virtual classes and so on.

Do you mean later on? As I see it, you do not have to learn about the things you do not use and can concentrate on the basics. Once you are comfortable and need to venture out into projects where other parts of C++ are used, you would need to, of course.


Yeah I think our views are mostly aligned.

I was pointing out that if you as beginner manage to set correct boundaries for C++, you still need to know what's on the other side in order to avoid it. You've constrained yourself to smaller language (a good thing), but you haven't eliminated all the baggage / mental overhead that rest of C++ brings. The optimal approach would be to pick a language that's already well suited to problem. I would always choose enhanced C over degraded C++.


Yeah, I certainly agree that the features cost you even if you do not use them.


Yes, that is basically "C++ with some certain libraries and the discipline - or static analysis enforcement - to only use part of the features."


That's basically modern C++, if you cut out all the things that aren't slices, destructors, and copy/move semantics.


I believe D has most if not all of those. There is even an official subset of the D language called “better C”.


DasBetterC does indeed have slices, destructors, copy semantics and some move semantics. There's a proposal in the works to add complete move semantics.


Neither of them have stable ABI's


This probably needs some context ... C at the time was still developing, lots of stuff was optional, parameters were int if you didn't define their type. V6 unix was a decade old and already wouldn't compile on K&R compilers, struct became genuinely unique types (requiring the creation of union, because struct could no longer be tweaked to do the same thing).

This was written at the end of that period where most people had an understanding of 'how it should be', while others were still using some of the older idiom ....


Instead of the second, I'd rather put: "Thou shalt understand pointers, before using them"


The second item is warning against a particular misuse of pointers that was apparently widespread at the time. On VAX Unix, it happened that the memory at address zero of a process was readable and contained zeroes. So a lot of code would misuse a NULL pointer as being equivalent to a pointer-to-an-empty-string, for instance: worked fine on the VAX!. So it's kind of a specific flavour of commandment 10. These days the common machines don't have a readable address zero, and all the old non-portable code has faded into history.


right. compat for this still exists on solaris at least, as lib0@0: see the notes section at the bottom of [0].

[0] - https://docs.oracle.com/cd/E19683-01/816-0210/6m6nb7md6/inde...


That could enable optimization. The compiler could remove many NULL-pointer checks.

On many platforms, all that is required is a change to the compiler. It could emit a ".quad 0" or equivalent, in a common data section at absolute address zero. Some platforms would require linker changes or even kernel changes.


16-bit x86 also had the interrupt handler table at linear address 0, I seem to recall some compilers for DOS that would make NULL point at that.


Yes. At least writing to interrupt vector table usually crashed your computer right at the point. I remember a certain DSP architecture that system flags near zero address. It was an interesting experience to debug a program that failed because a write to struct member through null pointer switched the machine to a different instruction set.


Every MMU-less micro lets you read address 0.


A lot of micros have MPUs that'll catch address 0 accesses without a full MMU. AFAIK all ARMs newer than ARM7 (ie. ARMv5) have one for instance.


Yeah, they will, if you activated it. And if you made access to 0 address be caught explicitly ( you might have the MMU active but not have it configured in such a way)


Yes, I know and I agree, I just said I'd rather put a more broad message there


Can you program in C effectively without pointers?


Nope, therefore you cannot do it effectively if you do not understand them :)


Depends on what you mean by "effectively." If you wanna, say, do an exhaustive search over all 4-dimensional integer vectors in a rectangular region, and print off the ones that satisfy some relationship, you don't need pointers (nevermind what printf and string literals are doing under the hood). It's a wonderfully beefy desktop calculator, in that way. But for most applications, pointers are pretty much necessary.


Arrays in C (once passed to functions) are pointers, even when they use array syntax:

https://www.digitalmars.com/articles/C-biggest-mistake.html


You don't need arrays for the code I was describing: it's a nested for-loop on 4 ints.

But, yeah, that's a really common mistake.


You can program C effectively without pointer arithmetic. Storing copies of pointers for later is usually a bad idea.


Can someone explain #9?


At some point in the distant past symbol tables allowed symbols up to 6 characters long. Longer names were allowed but anything beyond 6 characters were gone by the time the linker was invoked. So ThisIsAFunction() and ThisIsAnotherFunction() would resolve to ThisIs(). It would hopefully produce an error at link time.



Better explanation than mine - thanks I learned something.


this and the tao of programming were foundational to my young mind in the nineties, but while the commandments somewhat hold true, the commentary aged a little.


I wish more programmers obeyed #7.


For C, obeying #7 is not even that difficult. It's much more of a challenge in C++ and probably Rust (and other languages).


> 7 Thou shalt study thy libraries and strive not to reinvent them without cause, that thy code may be short and readable and thy days pleasant and productive.

> Numberless are the unwashed heathen who scorn their libraries on various silly and spurious grounds, such as blind worship of the Little Tin God (also known as ``Efficiency''). While it is true that some features of the C libraries were ill-advised, by and large it is better and cheaper to use the works of others than to persist in re-inventing the square wheel. But thou should take the greatest of care to understand what thy libraries promise, and what they do not, lest thou rely on facilities that may vanish from under thy feet in future.

I'm not sure I follow. Why this would be difficult in any language with a usable package manager and a reasonable ecosystem?


Most people don't even know what's available to them in the standard library of C++ and under-use things in it. Especially STL algorithms but not just that.


I was with them until "one true brace style". The rest are good advice.


Same but for perhaps a different reason

> As a lamentable side issue, there has been some unrest from the fanatics of the Pronoun Gestapo over the use of the word ``man'' in this Commandment, for they believe that great efforts and loud shouting devoted to the ritual purification of the language will somehow redound to the benefit of the downtrodden (whose real and grievous woes tendeth to get lost amidst all that thunder and fury). When preaching the gospel to the narrow of mind and short of temper, the word ``creature'' may be substituted as a suitable pseudoBiblical term free of the taint of Political Incorrectness.

Not sure that was necessary. If you happen to disagree that Language is a valid place to fight for gender equality, you'd better serve your cause ignoring calls to equalize your language, rather than go on an anti-PC rant that smacks of an alt-right /r/unpopularopinion post. Just Another Old Man Yelling At Clouds.


> If you happen to disagree that Language is a valid place to fight for gender equality, you'd better serve your cause ignoring calls to equalize your language

It's not fair to say that people who disagree should stay silent.


Yep, that remark was an unforced error that has not aged well.


Language is not a place I can leave or join as I please.

We're stuck with language.


> If you happen to disagree that Language is a valid place to fight for gender equality, you'd better serve your cause ignoring calls to equalize your language, rather than go on an anti-PC rant that smacks of an alt-right /r/unpopularopinion post.

What if you happen to want to signal solidarity with the alt-right crowd? Why assume a flamboyant alt-right-style rant is an accidental coincidence? (Nto sure of the 1990 date is for the commandments, the annotations, or both, but in ant case, while it wasn't called the alt-right then, the subculture and attitudes certainly existed at the time this was written; 1990 would have been well into the first wave of it's vigorous embrace of flamboyant attacks on “political correctness” as a signal of group identity, which started in the mid-1980s as I recall.)


The PC movement began well before the 1980s.


> The PC movement began well before the 1980s.

There's no such thing as “the PC movement”; every ideological movement has ideas of correct usage of terminology related to the ideas that motivate the movement, the term “political correctness” has been used as a derogatory term for different of those ideas among different and unrelated ideological movements at different times. (e.g., in the 1930s-1950s it was used in a New York times article describing Nazi drive for uniformity in expressed ideas, as well as by American Socialists attacking the American Communists.)

However, attacks against expression of anti-sexist and anti-racist ideas as “political correctness” by the same segment of the American Right has been extremely popular twice, the first in the 1980s-1990s, and the second we're in right now.


Then that's strong evidence against their reasoning abilities and I don't trust much of anything they have to say, so, fair point.


> Beware, in particular, of the subtle and terrible ``All the world's a 32-bit machine'', which is almost true today but shall cease to be so before thy resume grows too much longer.

That’s cute. What year was it written?



Yeah... the reference to the abundance of VAXen isn’t something one encounters often this side of the fall of the Berlin Wall.


Which side is that?


The outside


What about HN readers/commenters on the inside?


>Thou shalt study thy libraries and strive not to reinvent them without cause, that thy code may be short and readable and thy days pleasant and productive.

That's why my teacher ought to go to hell, how many times do I need to say that


There's a difference between re-implementing to understand, and re-implementing to ship into production.

It's common for a blacksmith to make a set of tools as a exercise, but they'll also commonly get some quality tools to do real work with.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: