16 ms·
Follow up to "The Unreasonable Effectiveness of C"
- ufo 14y agoI noticed that he didn't mention using some higher level scripting language on top of C. Is this an intentional omission?
- scott_s 14y agoHe answered that in response to the question that if C in Erlang was a problem, how was more C the answer: Because it's easier to debug when you don't lose context between the "application" layer and the lower level code. The big problem we've seen is when C code is getting called from higher level code in the same process, we lose all the debugging context between the higher level code and the underlying C code.
- bch 14y agoI'm regularly using Tcl to sling C around and when I run into issues, gdb is there -- is he talking about something different, or am I missing something?
- scott_s 14y agoHis point is that when you're using gdb in your C code, the higher level language that called your C code (Erlang, Tcl, whatever) is opaque. That is, if when looking at your C code, you realize "the only way this variable can have this value is if my higher level code has this other value..." you can't easily inspect the higher level code in your debugger. Unless gdb is more powerful than I'm giving it credit for. Does it allow cross-language debugging from Tcl to C, and back to Tcl?
- bch 14y agoWell -- Tcl happens to be difficult to debug w/ tools because it's so dynamic -- but that said, let me tell you what I run into, and how I resolve. I compile C (original C, or bindings to libraries) and enable all warnings, use Tcl C APIs to do C memory management (allows electric-fence like behaviour where I've got optional guards on allocated mem), and I'm pretty familiar w/ the Tcl C API. When something is horribly wrong, I'll get a core dump and the full stack trace will indicate the path from Tcl, on up into my bindings, and further into the library in question. From there, typically with a small amount of inspection and testing it's easy to isolate the problem area and fix. This way I've solve application (Tcl script) code, my library bindings, and errors in 3rd party (open source) libs -- I've got no doubt that there's room for improvement in my process -- either by tools or techniques. That said, I feel productive and happy with what I've got going on now. When I want performance in Tcl, I punt and push it to C. When I want dynamic control or nice interfaces, I punt and drive it with Tcl.
- scott_s 14y agoI think that's a reasonable process, and probably the best you can do with current tools. But even though it's reasonable given your software stack, it's still much more involved than just using gdb on C code. (Note that I'm not arguing that it's never worthwhile to use a higher level language to drive C code, just that I think Katz has a valid point regarding debugging.)
- niggler 14y ago" I'm pretty familiar w/ the Tcl C API" The Tcl C API is fairly simple, and that's by design. There's a very slim chance you loused something up in the interface. Dealing with the interface from Erlang, or with many other higher level languages, is like pulling teeth.
- ay 14y agoI think it is covered by this part: "If a big problem was C code in Erlang, why would using more C be good? Because it's easier to debug when you don't lose context between the "application" layer and the lower level code. The big problem we've seen is when C code is getting called from higher level code in the same process, we lose all the debugging context between the higher level code and the underlying C code." OT: My personal best experience with interfacing a higher level language with C from the debugging standpoint was a C+Lua combo, and even then it was far from optimal.
- sramsay 14y agoIt's never optimal, and often, it's the source of truly infuriating bugs. Yet for all that, people don't say, "Hey, let's skip the middle man and just call libcurl or libxml or whatever from C. Because you know, these are C libraries." I think they don't do that because they've been told a hundred thousand times that C is for low-level bit fiddling, that manual memory management is impossible, that it's tedious and difficult to write, that it's a "systems language." Honestly, if you haven't programmed in C since college, you should give it a try -- especially if you're on Linux. The tooling and library ecosystem of C is absolutely second to none, and there's an enormous community out there that consists of some of the smartest programmers you will ever meet. I agree with you about C+Lua. I also notice that people who seriously do that are serious C hackers -- which, I suspect, is seldom the case with most users of Python and Ruby.
- betterunix 14y ago"The tooling and library ecosystem of C is absolutely second to none, and there's an enormous community out there that consists of some of the smartest programmers you will ever meet." Conspicuously absent from this statement is, "the language features make you more productive," or, "smart programmers using this language are doing things people thought were impossible." The issue with C (and even more so with C++) is that the language features almost always work against you.
- sramsay 14y ago
- anigbrowl 14y agoI hated and feared C for years. Then I finally learned it and fell in love with it. Now other languages seem like too much work. I'm only a hobby programmer so that devalues my opinion somewhat (insofar as I don't have to support large production systems or please committees), but one of the things I love about C is that once you have something working in C, you're likely done - if you need to go faster or better, then either your understanding of the problem or the algorithm you're employing is flawed, or maybe you need to do some bits of it assembler (DSP for example). The other thing is that even though C is old it still work great. I don't know how you web guys keep up with so many 'frameworks of the month' and so forth. I took up C mainly because I was tired of things becoming obsolete before I had got around to learning them properly.
- tptacek 14y agoOne of the greatest things about coming back to C from years of Ruby is that you can constantly tell yourself "I don't need to worry about performance because there's no way what I'm doing here could be worse than what Ruby was doing for me". It's hard to fully articulate the feeling but it's great; it's like a cure for premature optimization.
- euroclydon 14y agoIs it possible to need C and not know it, or if I need it will I know it? Because I can't think of anything I'd use it for. You guys speak of it and other higher level languages as if you use them interchangably for the same tasks.
- tptacek 14y agoI use Ruby for things that deal with the web, for utility programs, and (most often) for software I'm not going to need to support long term, such as clients for bizarro network protocols I encounter on penetration tests. I used to use C for everything else; I'd reach for Go first now, but I still love C. One way to think about C vs. (say) Python is that it's like the relationship between an FPGA and an ASIC: you prototype in a high level language and you write C when you really know exactly what you need your program to do. C is not a great exploratory programming environment, but it is excellent when you have a specific plan.
- haberman 14y ago> I used C++ inheritance, templates, exceptions, custom memory allocation and a bunch of other features I thought were very cool at the time. Now I feel bad for the people who have to maintain it. I think this is right on the money. There are a lot of things you can do with C++ (and other languages -- even C probably) that feel good at the time, only to learn later that they don't age well. I've never seen it analyzed deeply why this is, but I suspect it has something do with how "fungible" the code is when you're done. Will your design let you make small design changes with relatively small and localized code changes, or has your complicated template/inheritance-based design "locked up" your code into a particular pattern, where changing any of the design assumptions requires "unwinding" a highly intertwined structure? I don't know the rigorous answer to this question, so I design with various heuristics, which mostly boil down to some version of "this is getting a bit too complex or too highly leveraged." What I mean by "leveraged" is that some significant guarantee or invariant is achieved through a complicated contract between two different objects. I try to keep the design of every individual type/object as "flat" and unsubtle as possible; again vague terms, but I know it when I see it.
- ggchappell 14y ago> ... I suspect it has something do with how "fungible" the code is when you're done. Will your design let you make small design changes with relatively small and localized code changes, or has your complicated template/inheritance-based design "locked up" your code into a particular pattern, where changing any of the design assumptions requires "unwinding" a highly intertwined structure? I'd say that this is right on the money. I think it is true that hardcore OOP (along with similarly complicated constructions) gives benefits to the designer who chooses a good and appropriate structure. But, due to the idea you mentioned, it severely penalizes even mildly poor designs, or designs that need to change.
- api 14y agoI think hardcore OOP is highly overrated outside of a few use cases where it does seem to work well: graphical user interfaces and certain kinds of business logic. In those two cases, OOP works because it correctly models the underlying problem. For GUIs for instance: A window is an object, a button is an object contained within a panel that is an object contained within a window... and so on. All of these are "drawable," and can receive mouse clicks, etc. OOP models that well.
- sutro 14y agoThat is one hell of a résumé.
- megrimlock 14y agoDefinitely! Of course, argument from authority is still relatively weak in situations where experts disagree, and that's definitely the case with programming languages. We can each find our gurus -- Damien Katz, Rich Hickey, Rob Pike, John Carmack, Mike Acton, Slava Pestov are some of mine -- but there's no absolute truth in programming debates. The best we can hope for is to share interesting insights, motivate them as clearly as we can, and then agree to disagree, each biased by our distinct experience.
- mrb 14y agoOf course the C language and compilers are so simple, and C sits at such a low level (right above assembly) that few things can go wrong in it (compiler bug) or under it (cpu bug). As people jokingly say, C is just a high level assembly language. If one tried to re-invent a language with C's properties, one would come up with C, again. For these reasons, I too expect C to remain the most performant and reliable high-level language baring any major change in computer architectures. Debating this fact would be the same as debating whether assembly is the most performant and reliable low-level language or not. Of course it is. (Preemptive reply to the doubter: as an example my 64-bit assembly implementation of MD5 is 75% faster that a 64-bit C implementation: http://www.zorinaq.com/papers/md5-amd64.html http://www.zorinaq.com/papers/md5-amd64.html ) And of course, performance and reliability don't always need to be #1 priorities, therefore, as the author says, "most every popular language has uses where it's a better choice."
- jzwinck 14y agoComputer architecture has already changed, with today's PCs having many logical processors. And indeed C lacks any direct affordance for parallelism. Good old pthreads are hardly adequate for many tasks compared to facilities in other languages. Yes, you can implement most of the needed features in C, but often without the grace or safety available elsewhere.
- pbsd 14y agoC11 adds thread and atomic op support: https://en.wikipedia.org/wiki/C11_%28C_standard_revision%29 https://en.wikipedia.org/wiki/C11_%28C_standard_revision%29
- mrb 14y agoPerhaps you are right. Perhaps a technological advance in compilers and languages so deep as to dislodge C is needed to fully solve the ease of programming of many-core computers... Something the industry has been trying to achieve for more than a decade.
- abecedarius 14y agoPart of its apparent inevitability now comes from its influence. Bliss was a reasonable competitor at the time with significant differences: expression-oriented, reducible control flow, immutable variables (you used something like ML's refs when you needed assignment, but stack-allocated). C started simple, but grew kind of complex. I'd like to have an ubiquitous simple mid-level language.
- marze 14y ago>I don't know a lot of what's out there on the horizon, and there are some efforts to create a better C. Are there any efforts to extend C to add very simple/light objects, and perhaps string handling?
- jrajav 14y agoThis sounds quite a bit like Objective C.
- bunderbunder 14y agoObjective-C's object model is very heavyweight. Granted, that's what I used to like about it (I haven't worked in it in years). You got to have this very high-level object-oriented language with all sorts of delightful features such as dynamic dispatch, duck typing, and even monkey patching. But you also got to have straight C sitting right there in the same language, and could easily flip back and forth between the two without incurring penalties that TFA mentions such as losing context at a language boundary when you're trying to debug code.
- podperson 14y agoI don't think it's fair to call it heavyweight. It's both high and low level at the same time, which is part of its awesomeness (there are no "methods" -- only messages (symbol names) so you can send objects messages (dynamic, has an overhead) or use a message to get a hard reference to a function pointer ("selector") and call that directly with no overhead (beyond a function call). So you can be nearly as dynamic as JavaScript or Python, or as performant as C without changing languages.
- ripter 14y agoC++ and Objective-C started with this goal. Objective-C started as a pre-processor for C.
- npsimons 14y agoSo did C++.
- tikhonj 14y agoI've recently realized that--at least to me--C is actually very much like Prolog. How? Well: Prolog is a fairly simple, Turing-complete language. For the things it's good for, it's great. But those things are few and relatively specialized. I could use Prolog for general-purpose programming, but I wouldn't want to. With Prolog, the question is always "why Prolog?" rather than "why not Prolog?". Sometimes there is a good answer to this, but usually there isn't. I can also get some of the benefit by using a DSL embedded inside a more general-purpose high-level language. I've thought this for a while, almost ever since I learned Prolog. Make no mistake: I actually rather like Prolog. But I haven't been using it very much. The recent revelation is that C has all the same characteristics. And in a similar way, while I still like C to whatever extent, I'm going to avoid using it unless I really have to. On a mostly unrelated note, I agree that Rust looks very promising. It's the new language that I'm the most excited about, especially after being let down by Go. Also, I'm not quite sure why he thinks the Rust syntax is odd: to me it seems extremely C-like, with some nice improvements (like implicit returns).
- bcoates 14y agoOut of curiosity, what are you hoping to get out of Rust that Go let you down on?
- tikhonj 14y agoThe best summary would be that I want a language to replace C++ but more sane and functional. Go is more like a language to replace Java and is most definitely not functional. Essentially, I don't see why I would ever use Go over Haskell or OCaml. The main areas where Haskell and OCaml are ill-suited are the lower-level ones currently dominated by C/C++ and Go does not seem to address those very well. The main areas Go is doing well, like server-side code, are very well suited to Haskell and OCaml and so I have no reason to drop down to a less declarative language like Go. Rust, on the other hand, seems to be targeting C++ directly. It also doesn't hate functional programming. So it perfectly fills the C/C++ shaped void in my current toolbox.
- dysoco 14y ago
- znmeb 14y agoI'm with you 1000% percent here. The only language I ever encountered that could possibly have supplanted C was FORTH, and it was doomed by legions of Unix-trained C programmers once the hardware got good enough to support C.
- gnuvince 14y agoWhat about Pascal? Seems like a simple, block-based language with the same functionality as C. Apparently, the only complaint against it is that its users like to eat quiche.
- sampo 14y ago"What about Pascal?" The type system, and control flow structures, were more strict and allowed less "abuse" (flexibility) than C. Strings were fixed-length arrays of chars, which was also less flexible than strings in C. Also people felt the begin-end block syntax less fashionable than C's {}. Take a look at: http://www.lysator.liu.se/c/bwk-on-pascal.html http://www.lysator.liu.se/c/bwk-on-pascal.html
- barrkel 14y agoBWK's rant on Pascal is about as relevant today as a critique of original C (no prototypes, types defaulting to int, etc.). In other respects (e.g. strong type safety) Pascal's approach "won", depending on your perspective.
- barrkel 14y agoNo unified standard across implementations, modern implementation dominated by a single vendor (Delphi) with an aging userbase and downward trend. And when you dig into the details of Delphi, you'll find various compromises caused by competitive pressure pulling one direction, backward compatibility pulling in the other.
- xentronium 14y agoThere is no particular benefit in switching from C to Pascal.
- dougk16 14y agoCan't really argue with anything specific here, but this and the last article's general premise seems like, "if you have a choice, you might want to go with C for these reasons...". The problem is, I can't remember the last time I had any practical choice between C and a higher level language. I'd love to use C more, but the decision is almost always made for me by a client, or a useful framework/library that only exists in language X, or a platform, or a boss.
- DannoHung 14y agoOkay, say I'm gonna start using C more seriously: What library do I use for strings? Not fucking arrays of 8 bit characters. Real Unicode compatible strings with concatenation and comparison operations and all that good stuff. And if it works with a regex engine, that's nice too.
- geoka9 14y agohttp://site.icu-project.org/ http://site.icu-project.org/
- DannoHung 14y agoHmmm.... > Strings are the most common and fundamental form of handling text in software. Logically, and often physically, they contain contiguous arrays (vectors) of basic units. Most of the ICU API functions work directly with simple strings, and where possible, this is preferred. Nope. Though the UText API was promising... unfortunately, it is totally incomplete.
- luser001 14y ago... which seems to be written in C++ (based on clicking around in the source tree for a minute). https://ssl.icu-project.org/trac/browser/icu/trunk/source/common/dictionarydata.cpp https://ssl.icu-project.org/trac/browser/icu/trunk/source/co...
- kenko 14y agoInteresting that among the other languages he mentioned one did not find Fortran or ML, which, I believe, were the go-to examples of C-beating languages in the discussion of the initial piece.
- robomartin 14y agoI remember what scared me to death with C++ when I was using it with frequency was the potential to end-up with these horrible inheritance trees that could really bungle a project in so many ways. If you didn't take the time to really, really, really think through your class hierarchy you could really shaft yourself in a big way. Bacause of this, as life went on I started to really appreciate the idea of composition vs. inheritance. For me C has always been an easy no-brainer go-to language to get things done, particularly so when performance was at stake. I've always thought that learning programming should start at the lowest possible level (yes, assembly), then move on to Forth, C and from there ideally Lisp before hitting Java for some OO love. With that kind of a foundation it's easy to learn and absorb just-about anything that comes your way.
- Someone 14y ago"I remember what scared me to death with C++ when I was using it with frequency was the potential to end-up with these horrible inheritance trees" I don't think you can blaim C++ for that. The time when 'we' hadn't learned the "composition over inheritance" lesson yet just happened to coincide with that of "let's write our framework in C++".
- robomartin 14y agoMaybe so.
- chj 14y agoMy thoughts on why C is effective: Simple. An average C programmer can easily learn 90% of the language and use 80% on a daily basis. So C programmers can understand each other generally well. Although different projects usually have different styles, they are very minor differences. Assembler friendly. You can link C code and assembler together with negligible overhead. Almost every performance demanding project has its busiest part written in assembler. Even though sometimes C is lack of a certain construct that you require, you can always implement it in assembler and connect it with C code (longjmp as a good example). Using assembler may seem to be contradictory to the first point, but remember only a handful of people need to work at such a low level, other people just use the C interfaces. Reusable. C has a huge set of robust and portable libraries. Their authors are proven to be surprisingly disciplined. However, we have to admit writing good C code is very hard. And I can see that less and less people will use it going forward. Steve Jobs' "trucks and cars" metaphor applies here too.
- deleted 14y ago[deleted]
- mimog 14y agoHis argument now seems to be that you have to use C for speed. In my experience that doesn't necessarily hold true anymore, given modern computer architectures and what JIT compilers are capable of. I have several times written something in a modern language and then convinced myself that I could get a large speedup if I instead wrote it in C, only to discover that the speed benefits were minimal at best and would require an exorbinant amount of exquisite hand optimization to increase further.
- larsmak 14y agoI started out with Visual Basic about 10 years ago, as an introduction to programming it did it's job well. I then moved on to C/C++ as I started my MSCS. It was great for doing implementation of algorithms and image processing. Working relatively low level, optimizing for speed and handling garbage collection yourself. As I started my professional carrer I went on to Java, and I've never looked back. The environment is great - I know how to implement algoritms and persistence-framework myself, but that's not what I'm getting paid for. There's always some high quality open source library/framework I can use. And sometimes when I need the "unreasonable effetiveness of C" I will interface with one of it's applications via JNI, I've done this several times: ImageMagick, ffmpeg, OpenCV, etc. I also onload a lot of the performance critical tasks to systems written in C/C++ like MongoDB, Redis etc. But Java can be fast as well, just ask Cassandra and Solr/Lucene. Java allows me to get my job done, quickly and effectly. And to write well structured, understandable code that most likely will be understandable in decades to come.
- nnq 14y agoIf they would keep putting the extra effort in debugging the Erlang VM C code, the benefits of this debugging would be available to the entire community of developers using Erlang. Now they are in their small corner of the world and every bug they squash is just a bug of their project. Overall it's worse for "the world" and better for them. This makes sense for commercial software but it's weird when you think about an open-source project. Just imagine if all the effort in porting Ruby/Lisp to Java/C++ or similar translations for big projects would have been invested in improving the VMs for these dynamic languages (yeah, most of these rewritten projects didn't have experienced C guys, but the OP certainly has and is one). Is bug-fixing and hacking on compilers and VMs really that hard? (I never approached these problems in practice because I've never had to scale something that hard and squeeze that last drop of performance, so I'm really asking the question, it's not rhetorical).
- randomsearch 14y agoIn academic circles, many struggle to understand why people are still using C for large projects, other than the special cases of operating systems, embedded systems, and code that must execute very quickly - e.g. within the gaming industry. The main argument against using C seems to be that C is at too low a level of abstraction, which leads to low productivity and buggy code. For example, pointer arithmetic might sometimes be useful, but it doesn't seem like something most developers should be exposed to anymore. I have some sympathy for this argument, but wonder what others think? - The right tool for the job? RS
- pjmlp 14y agoIt is so funny in these debates to see people always mixing languages with their default implementations, as if they were the only one available for the language.
- StephenFalken 14y agoI like the way Alexander Stepanov, primary designer and implementer of the C++ Standard Template Library (STL), decribed the C Programming Language in an interview: "Let's consider now why C is a great language. It is commonly believed that C is a hack which was successful because Unix was written in it. I disagree. Over a long period of time computer architectures evolved, not because of some clever people figuring how to evolve architectures---as a matter of fact, clever people were pushing tagged architectures during that period of time---but because of the demands of different programmers to solve real problems. Computers that were able to deal just with numbers evolved into computers with byte-addressable memory, flat address spaces, and pointers. This was a natural evolution reflecting the growing set of problems that people were solving. C, reflecting the genius of Dennis Ritchie, provided a minimal model of the computer that had evolved over 30 years. C was not a quick hack. As computers evolved to handle all kinds of problems, C, being the minimal model of such a computer, became a very powerful language to solve all kinds of problems in different domains very effectively. This is the secret of C's portability: it is the best representation of an abstract computer that we have. Of course, the abstraction is done over the set of real computers, not some imaginary computational devices. Moreover, people could understand the machine model behind C. It is much easier for an average engineer to understand the machine model behind C than the machine model behind Ada or even Scheme. C succeeded because it was doing the right thing, not because of AT&T promoting it or Unix being written with it."