logo

drewdevault.com

[mirror] blog and personal website of Drew DeVault git clone https://hacktivis.me/git/mirror/drewdevault.com.git

Lessons-to-learn-from-C.md (4474B)


  1. ---
  2. date: 2017-01-30
  3. # vim: tw=80
  4. title: Lessons to learn from C
  5. layout: post
  6. tags: [C, language design]
  7. ---
  8. C is my favorite language, though I acknowledge that it has its warts. I've
  9. tried looking at languages people hope will replace C (Rust, Go, etc), and
  10. though they've improved on some things they won't be supplanting C in my life
  11. any time soon. I'll share with you what makes C a great language to me. Take
  12. some of these things as inspiration for the next C replacement you write.
  13. First of all, it's important to note that I'm talking about the language, not
  14. its standard library. The C standard library isn't *awful*, but it certainly
  15. leaves a lot to be desired. I also want to place a few limitations on the kind
  16. of C we're talking about - you can write bad code in any language, and C is no
  17. different. For the purpose of argument, let's assume the following:
  18. - C99 minimum
  19. - Absolutely no code in headers - just type definitions and function prototypes
  20. - Minimal use of typedefs
  21. - No macros
  22. - No compiler extensions
  23. I hold myself to these guidelines when writing C, and it is from this basis that
  24. I compare other languages with C. It's not useful to compare bad C to another
  25. language, because I wouldn't want to write bad C either.
  26. Much of what I like about C boils down to this: **C is simple**. The ultimate
  27. goal of any system should be to attain the simplest solution for the problems it
  28. faces. C prefers to be conservative with new features. The lifetime of a feature
  29. in Rust, for example, from proposal to shipping is generally 0 to 6 months. The
  30. same process in C can take up to 10 years. C is a venerable language, and has
  31. already long since finished adding core features. It is stable, simple, and
  32. reliable.
  33. To this end, language features map closely to behaviors common to most CPUs. C
  34. strikes a nearly perfect balance of usability versus simplicity, which
  35. results in a small set of features that are easy to reason about. A C expert
  36. could roughly predict the assembly code produced by their compiler (assuming
  37. `-O0`) for any given C function. It follows that C compilers are easy to write
  38. and reason about.
  39. The same person would also be able to give you a rough idea of the
  40. performance characteristics of that function, pointing out things like cache
  41. misses and memory accesses that are draining on speed, or giving you a precise
  42. understanding of how the function handles memory. If I look at a function in
  43. other languages, it's much more difficult to discern these things with any
  44. degree of precision without actually compiling the code and looking at the
  45. output.
  46. The compiler also integrates very comfortably with the other tools near it, like
  47. the assembler and linker. Symbols in C map 1:1 to symbols in the object files,
  48. which means linking objects together is simple and easily reasoned about. It
  49. also makes interop with other languages and tools straightforward - there's a
  50. reason every language has a means of writing C bindings, but not generally C++
  51. bindings. The use of headers to declare external symbols and types is also nicer
  52. than some would have you believe, since it gives you an opportunity to organize
  53. and document your API.
  54. C is also the most portable programming language in the world. Every operating
  55. system on every architecture has a C compiler, and they weren't really
  56. considered a viable platform until it did. Once you have a C compiler you
  57. generally have everything else, because everything else was either written in C
  58. or was written in a language that was implemented in C. I can write C programs
  59. on/for Linux, Windows, BSD, Minix, plan9, and a dozen other niche operating
  60. systems, or even no operating system, on pretty much any CPU architecture I
  61. want. No other language supports nearly as many platforms as C does.
  62. With these benefits acknowledged, there are some things C could do better. The
  63. standard library is one of them, but we can talk about that some other time.
  64. Another is generics; using void* all the time isn't good. Some features from
  65. other languages would be nice - I would take something similar to Rust's match
  66. keyword. Of course, the fragility of memory management in C is a concern that
  67. other languages are wise to address. Undefined behavior is awful.
  68. Even for all of these warts, however, the basic simplicity and elegance of C
  69. keeps me there. I would love to see a language that fixes these problems without
  70. trying to be the kitchen sink, too.
  71. In short, I like C because **C is simple**.