For anyone who hasn't browsed through Peter Seibel's "Coders at Work," one of his subjects is Fran Allen...it's kind of funny because I do agree that learning C has been valuable to the high-level programming I do today (but only because I was forced to learn it in school). But there's always another level below you that can be valuable...Allen says C killed her interest in programming...not because it was hard, but because of, in her opinion, it led engineers to abandon work in compiler optimization (her focus was in high-performance computing):
Seibel: When do you think was the last time that you programmed?
Allen: Oh, it was quite a while ago. I kind of stopped when C came out. That was a big blow. We were making so much good progress on optimizations and transformations. We were getting rid of just one nice problem after another. When C came out, at one of the SIGPLAN compiler conferences, there was a debate between Steve Johnson from Bell Labs, who was supporting C, and one of our people, Bill Harrison, who was working on a project that I had at that time supporting automatic optimization...The nubbin of the debate was Steve's defense of not having to build optimizers anymore because the programmer would take care of it. That it was really a programmer's issue....
Seibel: Do you think C is a reasonable language if they had restricted its use to operating-system kernels?
Allen: Oh, yeah. That would have been fine. And, in fact, you need to have something like that, something where experts can really fine-tune without big bottlenecks because those are key problems to solve. By 1960, we had a long list of amazing languages: Lisp, APL, Fortran, COBOL, Algol 60. These are higher-level than C. We have seriously regressed, since C developed. C has destroyed our ability to advance the state of the art in automatic optimization, automatic parallelization, automatic mapping of a high-level language to the machine. This is one of the reasons compilers are ... basically not taught much anymore in the colleges and universities.
Actual song from PLDI'07 where she received the Turing Award, which we all sang to the tune of Take Me Out to the Ball Game:
Let’s all sing to Fran Allen
For the great things she’s done.
PTRAN and Blue Gene and E C S
Fran, we’ve gathered to toast your success.
As we ponder all you’ve accomplished,
Our colleague extraordinaire,
Here’s to you, Fran Allen, you’re truly beyond compare
Optimizing compilers
Parallel transforms too
Intervals, call graphs, and data flow
Keep our programs from running too slow
So we root, root, root for Fran Allen
Her heart, and spirit, and voice
For she’s won the Turing Award and we all rejoice!
She said that she believes functional languages and programs are key for scalable parallelism on massively multicore processors, because of the unavoidable performance problems associated with synchronization on shared data dependences in imperative languages.
The back story you quoted about C motivates her position a little, so thanks. It seemed like few of the hardcore compiler people that I spoke to at the conference seriously believed functional languages were going to be the future because of performance reasons, although personally it doesn't seem like an entirely unreasonable proposition.
Using functional paradigm with immutable types does take care of a lot of the complexities of parallel computing... It allows you to make a lot of assumptions (from the underlying platform's perspective) and can break up work in very interesting ways, not just across cpu cores, but even in distributed computing environments. If you combine this with a scriptable language, you can even carry the workload with the code to operate on the load.. which takes things a bit farther. You could create a literal farm of workers that grab a bit of data, process it against the defined load, and then return the result with the next step to run against the data...
I've wanted to create such a system for a while.. right now the closest I could come up with would be to use nodejs with json and a message queue to handle requests/loads. Unfortunately, there's a pretty serious cost to the json serialization, and other issues... but it's an interesting idea that has merit. I think in the end such a system will have a quickly serializable binary expression of both the data and the work to be done.
The catch is that most developers I know aren't used to breaking work up in such a way that it could be very parallelized.
The kicker for me that makes me think that working too hard to make easily parallelizable constructs isn't worth it is that communication is expensive and single cores are actually pretty darn powerful on their own. The implication is that you don't want to be parallelizing at too low a level. You want to be doing it at a much higher level if you possibly can.
If you have an 8-core machine and thirty independent tasks at the top-level, then all the functional programming research and parallel algorithm wizardry in the world isn't going to make you want to parallelize anything except the top-level tasks. So even if that's a verbose and error-prone task due to procedural programming constructs, at least you only need to do it once. Heck, in my own (admittedly limited) experience 90% of the hard work I have needed done has been handled by my OS's process scheduler and Redis.
The fact is that business applications, the web, and consumer software are all perfectly happy to accept the current limitations of hardware -- 12 processes running on 4 cores is efficient and easy, even with no parallelization at all below the OS process level (with the possible exception of GUI threads in desktop applications).
The only really interesting work happens in areas like HPC where you have 1 task and 900 cores and if you can't parallelize you are dead in the water, and latency-critical applications where the sacrifices made to run intra-task parallelization pay big dividends.
I think with the increasing availability of more, weaker CPUs with a decent thermal envelope, and efficient processors like ARM, then distributing work makes even more sense... in a SOA system, where a lot of processing may well be IO bound, why not break out the load even more... I think the future will be thousands of compute nodes/workers along with hundreds of service nodes handling millions of simultaneous requests.
Functional constructs make such scaling nearly effortless once the practical issues of breaking up work are handled. Yes, communications has a cost, but there are faster channels available than what are used... and distributing data persistence into redundant, sharded clusters can yield a lot of other benefits.
Given, most line of business applications are fine on current hardware... the problem is scaling to 10x or 100x the workload. You can do this by creating a system that can scale horizontally, or to be more performance oriented with current hardware. One solution gains you a single generation of increased output... another gets you N scale expansion.
I don't think it's just macro parallel tasks... but many-micro tasks that can work within such a system.
You are missing the per-CPU parallelization via vectorization that lies at the core of every modern video decoding library. The conundrum with C is that it is one of the very few languages that allow (via assembler callouts) to directly use CPU vecorization instructions, but at the same time does so in a manner that absolutely prevents automatic optimizations (i.e. by observing data dependencies).
I think she might have given up on programming a bit prematurely. The pendulum has obviously swung completely the other way with high level languages like Haskell pushing forward compiler optimization, and JIT VMs pushing forward in other directions. It's actually an exciting time for "smart compilers".
> I think she might have given up on programming a bit prematurely. The pendulum has obviously swung completely the other way with high level languages like Haskell pushing forward compiler optimization
C compilers were optimizing long before Haskell. From her interview, I don't understand why she couldn't work on optimizers even if someone else advocated optimization being programmer's repsonsibility?
Right, and they've come up with some excellent tricks too. But the reason she felt optimization wasn't going to progress as far is because C is a lower level language than some of the other languages out at the time, and there are necessarily less tricks you can do in a lower level language because you have to infer the intent of the programmer more, and rely on optimizing idioms etc, rather than optimizing actual constructs of the language.
How does a compiler optimize a single "goto"? There isn't much it can do unless, for instance, it notices that the goto is found in an idiomatic pattern that results in a loop. Then it can make a decision whether to unroll the loop or not. If the language gives you the loop construct, it can skip the "recognize the idiom" step (and the associated risk of guessing wrong), and go right to optimizing loops. Similarly, in higher level languages than C, the programmer can express their intent more directly, and therefore the compiler can take less risks when guessing "Ah, I see what you're trying to do, here's the fastest assembly that accomplishes that"
To convince C users why Haskell has the potential (but currently only potential) to optimize better, it is best to just point to one example that C can never hope to optimize : deforestation.
C will never be able to do that. Before optimization : the programmer requests a list to be created, fill it by calling functions and then passes the completed datastructure list (or tree) along to another function, which executes commands according to what the list contains.
After optimization there is no more list. Instead the function the list is passed to will call a generated function that generates exactly the needed elements of the tree just-in-time. Result: no list, no memory (aside from 1 element on the stack), no allocation, no clearing of memory afterwards.
Of course the downside is that it's very tempting (and encouraged) to write programs that don't contain these optimizations you'd have to do manually in C/Java/... and just have them run. What you'll miss as a Haskell programmer is that the program is effectively dependent on those optimizations for it's complexity (for example: optimized program is O(n), program as written is O(n^n). Then you insert what looks like a tiny change, say, sorting the list, which prevents optimization from happening and boom, your binary switches from O(n) to O(n^n). All tests will obviously pass, yet your boss is unlikely to be happy ... At this point it is extremely hard to figure out what just happened)
While I'm very sympathetic to Allen's viewpoint, it seems that there was, and still is, a large class of problems where C-like languages (where the programmer does the optimizations) are better than high level languages with optimized compilers.
The best example for her case would be Fortran, where the language is both higher level, and faster, because the compiler can make much more assumptions (my understanding is the restrict keyword somewhat evens the playing field with C, but that is kind of a hack).
However, plenty of numerical work is also done in C, in spite of Fortran's availability.
writing optimizers in C is much harder than in Fortran because of reduced abstractions and reasoning about memory and pointers. in Fortran they were working on making automatic multi-threaded optimizations where you would write Fortran and it would auto-parallelize into multiple threads ... before C was invented.
C did kill a lot of work on making computers easier to program and safer. it was a devils bargain for speed and we paid for it with decades of crappy code with buffer overflows and shared state race conditions. it's tricky to know if it was worth it.
This is a fair point, but it brings to mind another point I didn't really understand till the last couple of years. Learning about how compilers work is just as important. Building a small lisp compiler was a life-changing experience for me in terms of going one level deeper, as much as understanding C was. For those who've never written lisp before, the reason I recommend a lisp compiler is that lisp compilers are the simplest to write, and the most expressive in terms of runtime strategy since lisp syntax mirrors a compiler's IR (intermediate representation). I think this is just as important in todays world because languages like Ruby and Javascript are both directly inspired by lisp. We also live in a world where Clojure is seeing a steady rise, for once a Lisp with large potential for significant commercial adoption.
I can highly recommend the book Lisp in Small Pieces, $93 on amazon, and worth every penny. Walking through the building blocks and design decisions of a language changes the way you code. Every language you look at winds up being internally translated into your own IR whether you've written a compiler or not. Understanding the inner workings of a compiler however adds depth.
Hell yeah, learning how to make compilers should be what a BS in CS is all about. Pretty much everything in computer science can be turned into a language and compilers have almost all of the major topics in CS as one easily explainable thing. It's also one of the few parts of CS that stands on a solid logical proof filled footing and is still insanely practical.
I basically teach baby compiler theory at the end of my Python book without people even noticing because I think parsing at a minimum is so important.
I think Forth may have that honor, and people have done some pretty amazing things with simple Forth implementations. I do agree, though, that writing a simple Lisp compiler is a worthwhile exercise, and the Lisp In Small Pieces is a book everyone should have on their shelf.
The LiSP book only describes self-hosting implementations while in Forth it's heresy to implement it in anything else than Forth or assembly. Well, perhaps Java implementations are excused for not being implemented in terms of themselves. :-)
Historically, the performance was pretty decent. I don't know how it stacks up against Hotspot today, but I note it does still seem to be a live project after >10 years.
We are talking about interpreters here, not compilers.
Binary Lambda Calculus has both Forth and Brainfuck beat,
with a BLC interpreter in BLC of only 206 bits (under 26 bytes).
Are you sure? From where I stand, it looks as though andrewvc and betterunix were both talking about compilers rather than interpreters, while dysoco didn't specify either, so I inferred that the compiler topic still stood.
I thought dysoco hinted at the brainfuck self-interpreter,
as linked to by peterwaller. There acutally is a brainfuck
compiler called awib (http://code.google.com/p/awib/), but
it's not that small (very artistic though). So I assumed
the discussion had drifted into interpreter territory...
I totally agree; actually a small, incomplete Scheme interpreter (which may be used to develop a lisp compiler later on) can be easily created in few hours (depending on used language) [0], without any prior experience. It's surely not as deep learning experience as building a compiler, but I think it's still worthwhile.
I do not understand the hype around clojure. I think functional programming languages have mainly evolved to introduce stronger typing and to remove the parenthesis. I wish a great future to scala (and haskell). For me, clojure is outdated.
I suppose it's because functional programming isn't a one-trick shop. There is a paradigm that comes out of lisp macros that can't be accomplished within a language like Scala or Haskell, even though those languages are superior in many other respects.
Clojure macros were designed in from the beginning, and thus a significant portion of Clojure core is built using macros. Also, to repeat an oft-stated argument, Clojure is homoiconic, making it much easier to treat code as data, and data as code, which dovetails quite nicely with the macro system.
> a significant portion of Clojure core is built using macros
Well, pretty much all the Scala compiler is written using macros, because compiler API ~= macro API.
Homoiconicity is nice, but the lack of it doesn't make anything impossible. If there is anything which makes stuff impossible, it's the static type system, which can catch most of your macro errors at compile time. That's a pretty good thing in my book.
The SICP Stanford videos by Sussman from the 80s and reading the book was an experience that sounds almost exactly like the author had learning C. It was one of the moments where I realized I enjoyed programming as much (or more) than design.
This is exactly how I felt when I started writing C.
I started out with .NET and Java. Both had quite high abstraction levels, and not much deep integration with hardware. I took my control statements, conditionals, and high-level object-based programming for granted -- I never WANTED to learn C. I took one look at K&R and was turned off by the insane amount of low-level work you had to do compared to Java or Python, even to write a simple character counter.
I came back to it. I was slow at first, I was confused, but I learned how to write in C. I learned how to control memory myself. I learned how to do my own text handling. I learned how to avoid buffer overflows and segfaults.
In many ways, it's like going from a Mercedes-Benz to a Miata. There's a lot less comfort, and you have to do a lot more of the shifting and oversteer yourself when the Benz used to do it for you, but you really feel yourself driving, and when you step back into the Mercedes, you feel numbed.
A small part of C was beaten into us for 2 years at the 11th and 12th grade. Today (I'm not a CS guy by the way), even when I write programs in python or any high level language I have this nagging feeling of 'loss of control' and that the code is not efficient enough. I know this is wrong but I can't help this feeling when now things are handed to you as compared to flipping every figurative bit in C.
It is right not wrong. Being decoupled from the machine by several layers of abstraction means you're just rearranging the furniture rather than whittling it out of wood.
I hate rearranging the furniture; it gives no satisfaction.
Satisfaction is a big part of quality in your life.
We need less code written in C, not more. We already have a problem with a massive, unreliable, insecure ecosystem of legacy C code that is hard to escape; writing more software in C makes that problem worse.
Most software is written to solve high-level problems. Using a high-level language is sensible, time-saving, budget-saving, improves portability, and saves on headaches later. The same rule that applies to COBOL should apply to C: only use it when you have to deal with an existing legacy codebase (and only if rewriting that codebase with a better language is not possible).
> We already have a problem with a massive, unreliable, insecure ecosystem of legacy C code
A ton of the world's software with the highest reliability requirements is written in C and C++.
Nuclear power plants? Yes. [1]
Joint Strike Fighter? Yes. [2]
Mars rover? Yes. [3]
Your Tesla? Yes [4]
US telephone systems. Stock exchanges. Bloomberg. Your cell phone OS (incl. many years before smartphones). The list goes on and on.
C and C++ are the most general and well-supported languages we have. They can solve problems on any architecture with a good tradeoff between efficiency and generality (over assembly) and predictable performance. Reliability and security requirements are up to the developer to impose on any language (see: the github PHP SQL injection search). C is not, in itself, a problem towards these goals and those who build upon C are always improving it [5].
"Reliability and security requirements are up to the developer to impose on any language"
This is a common fallback in these discussions, but it is misguided. Yes, you have to work to make software secure in any language; no, this does not mean C is equivalent. In C, you still need to worry about high-level problems like SQL injection, while simultaneously having to worry about low-level problems like integer overflows, dangling pointers, etc.
That critical systems have been written in C or C++ is not relevant -- it does not mean that it was a good idea to do so.
Well, I actually see that as an advantage vs. placing trust in an abstraction you have no control over that can provide security problems for you. So I guess we'll agree to disagree on this one.
Curious though, in what would you implement the examples I gave?
For the first two (nuclear power and JSF) and the car I would probably use a language like SML or Haskell, or perhaps even a language like Coq (where your programs are mathematical proofs of their own correctness). For a Mars rover, probably a core written in the languages above, and then bootstrap Common Lisp on top of that core (the core would control critical things that will not need much room to change, Lisp for various AI related things etc.).
Of course, I am not an expert on the requirements of all those projects. Maybe some fact about functional languages makes them entirely unsuitable. If there is a technical reason why C is being used, I would like to know it; if the reason is just, "Well that's what the libraries are written in, that is what most people know, there was a bunch of legacy code, etc." then it only proves that technical reasons are easily trumped by practical concerns. Like I said earlier, it is hard to get away from the large C and C++ codebase that we have to deal with today, despite all the problems of those languages and despite the widespread availability of better languages.
They took the code from the Ariane 4 and stuck it on the Ariane 5 assuming all would go fine.
While a famous incident attributed to Ada, I can safely say that C and other popular languages have done far more damage. Even if not in terms of exploding rockets (I don't know), but time lost debugging, fiddling with checks that would be handled in other languages and so forth.
I like to tell people with Ada I can spend my time adding value rather than fighting against the language because of it's minimalism and the bugs that come with that.
It's a very personal decision. :) You're not going to be popular on HN with a language like Ada. You're also probably not going to find a company looking for Ada developers, though I, myself, do Ada work for pay.
The Ada way of doing things really is a whole other world with completely different goals in mind than what fanboys and fangirls (I'm using the term dismissively, but there are real problems with new languages) will tell you about the new language they're using that was thrown together last weekend. Ada, of course, is far from perfect, but the blemishes like unbounded string syntax (I hope to see that fixed next revision! Ada just had a new revision!) are not enough to put me off from all the safety and checking the language does for me.
I must tell you that it was the winner of a DoD contest to create a kind of perfect language. There was a document called the Steelman that outlined everything the DoD's perfectly readable, maintainable, reliable, safe language would look like. Three of the four entries were Pascal-derived, not C!
If there is one thing Ada will do for you, if you let it, is demolish your ego. Every stupid thing you do will be caught by the compiler and you will scorned. The compiler will piss and moan catch all sorts of fantastic errors that you'd have to pop into a debugger for in C. Some folks have this notion that they are infallible, but "to err is human", right? You're welcome to turn off the checks in specific instances or project-wide (if you're nuts), but this isn't me. I'd love to think it is—and I write pretty great Ada these days—and I still don't have the gaul to turn off compiler checks.
Everything isn't a pointer in Ada, we can nest functions. Hell we nest packages and do sorts of things that just don't translate to Java, C++ or C, but now I'm just rambling.
I think Ada is a great choice for anything more than a shell script. Learning it introduces you more to a software engineering mindset because the language is built for software engineering, not hacking something together— though, in time, you will be capable of it. It's not the change of mindset like switching from procedural to functional, but it may be just as enlightening.
Well, since I'm not an American nor living in the US, DoD jobs are out of the question.
Secondly, I am unable to grok functional programming, which is why I quit trying to learn Haskell. I tried, I really tried but there's no way I'm able to wrap my head around functional programming. In my mind, there's a long list with two digits in hex, that the computer iterates as fast as possible. So if Ada is a functional only language that puts the brakes right there. If no, I'd be more than happy to start learning.
Ada ain't functional. A soft introduction is John English's Craft of Object-oriented programming. It's online, free, very intuitive and very well written. I usually tell folks to skip over the basics if they know them and work the first half. You're welcome to swing by #ada on Freenode for exceptionally friendly Ada talk. See what you think! I hope to see you on Freenode. :)
Once I read a story about a hardcore C developer that was forced to work on an Ada project.
In the beginning she was complaining a lot about the language's verbosity, but with the time she spent on the project she eventually became an Ada advocate! :)
That's a great anecdote. All to often you find when people are forced to do something they hate it no matter what, whether it's deserved or not. I'm guilty of this a bit myself. Ada had a DoD mandate in the 90s which really riled a lot of folks and put them off of the language for good. It's part of the reason Ada has not had more of an impact in our lives. That, and compilers for Ada were much more expensive then as well. For many many years though we've had GNAT, a free software project and GCC frontend. We are truly lucky to have it developed by it's corporate steward which is funded by dual-licensing the compiler for FLOSS and commercial support contracts.
No! Signed integer overflow in C/C++ is undefined. In other words, the language specifications permit implementations to do anything whatsoever[1]. This is emphatically not the case with either Java or C#. As an example, per the spec, with respect to C# integer multiplication,
In a checked context, if the product is outside the range of the result type, a System.OverflowException is thrown. In an unchecked context, overflows are not reported and any significant high-order bits outside the range of the result type are discarded.
In other words, while integer overflow isn't necessarily checked, unlike C/C++, C# isn't allowed to corrupt memory, violate runtime security guarantees, format your hard drive, threaten the President, or launch a video game[2] on integer overflow.
Several of your examples are hard real-time systems. Garbage collectors, schedulers, etc. are a no-go in such environments, so you won't see much Python or JavaScript there, but that doesn't discount the value of those languages. Note that Ada, a high level language, is used in similar systems, and that Lisp has been used in NASA satellites. High-level languages like Erlang are used in telecom systems and other critical network applications.
The fact is, languages created in the early history of computer programming have had the opportunity to be used in high profile projects like the ones you brought up. In time, you will undoubtedly see Python and others used in such contexts.
The use of C and C-likes by the JPL rather than Lisp is a sad story; it means robotics has not advanced as fast as it could have. http://www.flownet.com/gat/jpl-lisp.html
Not really. What we need is people not learning C (or any language) without also learning how writing it wrong causes defects. In my book (mentioned in the post) I have students using Valgrind and attempting to break their code starting at the 4th lesson. I also show them how and why to avoid defects in C.
Instead of saying "no new C", we should probably be approaching it with a two-pronged attack. First, tracking down bad educational material and making sure new C coders learn how to make safer C. Second, fixing the older code so that it is safe by default, rather than only in the context of the code it's written in.
But, yeah pipe dreams and all, so I just work on improving the educational material.
Thanks Zed, I really can't upvote you enough! I absolutely love the style of your writing, and the "hard-way" approach to teaching. Keep up the great work :-)
Was there any study done to the (un)reliability of C? I know for a fact practically every piece software I use is programmed in either C or C++.
The sole exceptions are Anki and Gentoo's portage system, both Python. And I'm pretty sure the reason portage is so extremely slow is because it is in Python (I've checked, it's not I/O-bound). And Anki is some very unreliable software.
In fact, give me a single big desktop software project made with a language that is not C or C++.
"I know for a fact practically every piece software I use is programmed in either C or C++."
How confident are you that that software will work as expected? How much are you willing to bet?
The fact that a language is popular does not prove that the language is good, nor that it should be used, nor that it is not causing us problems. Just the other day on HN, there was an article about a massive number of vulnerabilities in X11 applications -- all resulting from problems that you have in C and C++ but not in higher-level languages. Entire classes of bugs that are common problems in C are just not an issue in other languages.
Sure, it is possible to write unreliable code in high-level languages. It is just a lot easier to write unreliable C code, and C programmers are much more likely to do so (even those with years of experience).
Of course, that just dismisses the criticism of the language. But to say that it "should [not] be used" ignores the current landscape of engineers, employers and problems.
That quote is always annoying, because it applies equally well to all criticisms of any programming language in active use, but not all criticisms are created equal. A useful heuristic would actually help distinguish between reasonable criticism and inevitable kvetching.
I'm not betting anything. I'm just saying that it seems to me the advantages of higher level languages do not outweigh the disadvantages. Most of the software I use was written relatively recently, which means other program languages were available, yet C was chosen over them.
In fact, give me a single big desktop software project made with a language that is not C or C++.
I find your requirements odd and vague (why big? why desktop?), but speaking just for myself: Eclipse, jEdit, CyberDuck -- all written in Java.
I use plenty of applications written in C and C++ too, of course; but I think that's largely due to (1) inertia in the application development industry, and (2) it took a while for runtime environments like the JVM to perform well, so they got a bad reputation early on that's no longer really deserved -- but the reputation persists in the minds of many developers.
My parent's post said C was bad and software shouldn't be written in it. So I retort by talking about desktop software because this is an area where C and C++ rule supreme.
I specified big because big software projects carry more merit. A calculator written in your favourite language might be pretty handy, but it doesn't show your language can be used for real software. I use some Python scripts, but I don't see it in a lot of serious applications, apart from the dead slow portage and Anki, which is the most buggy software on my machine.
I don't think inertia is a real factor. Most software I use is brand spanking new. Google Chrome, to give an example, is barely five years old! Most of the other software I use is from the GNOME project, which has seen a major rewrite with GNOME 3 about two years ago, where they could have chosen to write it in a high-level language. Yet practically all of it is still in C, with a Javascript layer for the Shell (which I both love and loathe).
And speed is interesting. It might be due to old compilers/interpreters, bad programming habits or oldness, but all non C/C++/C# software I have ever used, was dead slow.
Google Chrome is based on WebKit, which was based on KHTML, which has been around since 1998. Moreover, Chrome depends on system and external libraries that provide C/C++ headers. Any viable alternative would need to work with C/C++ headers without needing large amounts of glue code, which isn't necessarily easy.
People still use C not because all of their code is so performance-sensitive that they can't deal with the overhead of bounds checks and garbage collection, but because there still aren't reasonably high-performance alternatives can easily integrate with existing codebases. Go and Rust are two promising contenders in this regard, but the former has only recently achieved C-level performance, and the latter is still not ready for production use. With that said, Mozilla is writing a browser in Rust (Servo), which shows their aspirations.
WebKit might be C/C++, that doesn't mean the browser itself needs to be that way. So is Anki, for example, a Python program that works with the QT toolkit, which is C++.
But point taken. I'm not saying we should use C, I'm anxious to a future where other languages can be used for serious applications. I was just trying to show C cannot possibly be that bad, as is it is still, together with C++, choice number one for every desktop application (and is Objective-C counts, it also dominates the mobile market).
My point in all this has been that language popularity is nearly orthogonal to technical pros/cons. Languages become popular for non-technical reasons. The popularity of C, C++, Objective-C, and related languages has almost nothing to do with the technical features of those languages, and almost everything to do with the marketing of popular OSes: Unix, Windows, and iOS. If an OS written in ML had become dominant in the 80s or 90s, it is nearly certain that ML would be a popular language. The inertia created by this large ecosystem cannot be denied; it is part of the reason you keep seeing new software being written in C/C++.
C absolutely is that bad. It is poorly defined. It forces programmers to explicitly write out things that can and should be done automatically. There is no standard error-handling system, just conventions involving return values and global error flags; there is no error-recovery system at all. Something as seemingly simple as computing the average of two signed integers winds up being non-trivial. C++ is even worse, as not only does it inherit most of the problems with C, but it introduces an entirely new list of pointless problems. Debugging code written in these languages is needlessly difficult -- you are spending as much time on high-level problems (i.e. design problems) as you are on tracing pointers and figuring out where some uninitialized value became a problem. It is not unreasonable to estimate that the dominance of C and C++ carry the cost of billions of dollars spent dealing with the headaches caused by these languages' problems.
It is hard to come up with a list of technical advantages to counter the above. C has few features, and those features are not very powerful. All that C really has going for it is that you can be "close to the machine," though it should be clear that other languages let you do this too (since other languages have been used to implement entire OSes). C++ has a few technical features that may be advantageous -- but they all compose poorly with each other, and their value is weighed down by all the baggage C++ carried from C (and indeed, most of the really bizarre bugs you can make in C++ stem from this baggage).
The non-technical reasons for C being popular vastly outweigh the technical deficiency of the language. The reason C/C++ is "choice number one" for desktop software is almost entirely a result of those non-technical reasons.
Nobody is doubting there's plenty of great software written in C. That doesn't mean we should choose C for all the new software we write, though. I'm sure one will find slow and unreliable code written in C if they look hard enough..
> And I'm pretty sure the reason portage is so extremely slow is because it is in Python (I've checked, it's not I/O-bound)
I was under the impression portage was "slow" (relative to other package management tools) due to the fact that it built everything from source (for which it uses make). Where is the Python bottleneck?
> In fact, give me a single big desktop software project made with a language that is not C or C++.
What constitutes "big"? There are a few large desktop projects that run on the JVM, for instance.
> I was under the impression portage was "slow" (relative to other package management tools) due to the fact that it built everything from source (for which it uses make). Where is the Python bottleneck?
I was talking about the overhead of making the list of packages to update/install. Pretending to install a simple package takes 7 seconds. Pretending to update takes 13 seconds. That's a very long time, because I might want to review the list of packages and make some changes, and every time I have to wait 13 seconds.
The compiling part is true, but that is not supervised.
It's been a while since I used Gentoo, but most of the serious users consider build-from-source as a feature and don't penalize portage for that. I believe your parent is referring to the sometimes annoyingly long dependency computation time of something like emerge -uDN world.
A major part of Firefox (hundreds of KLOC) is written in JavaScript. While the layout and network code is all C++, most parts that aren't performance-critical and don't need to interact directly with the OS are JS. This includes all of the high-level UI code.
I'm not siding with or against you here, but each of your examples is of something originally being in a language other than C.
Your position isn't strengthened if you can only name systems that were written in something else before someone converted them to C. In fact, by design, that's kind of benefitting the opposing side. I'm just saying.
1) the original UI for Skype was written in Delphi. The core functionality is, and has always been written in C/C++.
2) Mac OS is not a desktop application.
3) Adobe Photoshop is all C/C++ now. They converted it to C/C++ because they decided that was a better choice. Its tough to sell that as a case for a major desktop application not in c/c++.
The parent poster asked for desktop software written in languages besides C or C++ without any reference of hybrid applications or timeframe when they were written.
Since when desktop operating systems are not desktop applications?
I can provide other examples, but most likely I will get extra requirements along the way, so why bother...
After all, you can always use the argument that any application needs to call C APIs when the OS is written in C, therefore all applications are written in C.
What a victim complex. If someone is debating that we should stop using C, and I ask for software not written in C, it's obvious that I'm looking for contemporary software. And the reasoning that every software is "C" because it needs to do system/library calls would be ludicrous, and to provisionally accusing me of that is insulting.
I've done some research myself, and there are some interesting and big projects in languages other than C. Eclipse in Java, Dropbox in Python to name two. But my point still stands. I looked at all the desktop applications I have installed and they're without fault C or C++.
My impression is that desktop software is/was largely written in C/C++/C#/Objective C/Objective C++ because those are the languages to which the Operating Systems of today expose their APIs. For example Win32 = C/C++, Cocoa = Objective C, Metro = C# (or I guess anything compiled to the Common Intermediate Language (CIL)???).
Now that said, most languages provide a bridging layer that allows them to call out to those "native" APIs. These are used to enable API ?wrappers?, however due to these being provided by third parties (I believe) there has been a tendency to gravitate toward the "blessed" language of the OS vendor.
One of the big advantages of Java (to me at least) was that it provided a platform independent windowing capability inbuilt within the JDK that has been maintained by Sun/Oracle/(and Apple) as new operating system revisions were released.
Note, for example, that C/C++/Objective-C/Objective-C++ programs aren't/weren't allowed in the Mac App Store (I'm not sure if this is still the case...).
(Personally I ported a Java App to Objective C++ due to this.)
But generally I agree with your point that this isn't the only reason why C was so pervasively used. However, you also need to consider that a large number of programming environments and tools were specifically developed to aid C/C++ programmers, e.g. Borland C++, Visual C++, Code Warrior, XCode. It's also worth remembering that the GNU C Compiler and Debugger were import contributions to free software back in the day.
But also consider distribution of compilers etc. I think it is pretty fair to say that a lot of programmers learnt to program using Borland Pascal/C++ because at that point the Internet was not as accessible as today and copies of these could be "obtained".
The advent of Internet has not only allowed the distribution of compilers and environments for other programming languages, it has also meant that the languages used for backend systems, i.e. web servers and web applications, is irrelevant to the user's web browser.
Anecdotally, for safety-critical system software an issue with some languages other than C is that they have not been suitable for real-time systems. I don't know much about this other than that exception handling and also garbage collection can cause issues due to their non-determinism.
I fear that you'll think that the above is a bit too much like saying "all software is 'C' because it needs to do system/library calls", however I think it's probably fairer to say "all software is 'C' because many people have really, really liked it" and "better the devil you know".
There is a lot of applications in C#, a lot in Java, a lot in full python (e.g. ubuntu utilities), some in flex (cheers to balsamiq the wonderful). The fact that you didn't installed them doesn't mean they aren't there.
Moreover, you shouldn't say C/C++, they are very different languages and I can bet my hat that your desktop applications are full of C++ with an high level framework like Qt. Not really close to the metal.
The desktop client is indeed written in Java Swing. Fun fact: for PDF printing and getting updates, it actually does interact with a web service in the Ruby on Rails application. Both are ungodly bits of code put together years ago which shame me but seem to continue functioning.
To be honest, I was looking for some more recent software. Skype is 10 years old and both Mac OS and Photoshop are both decades old. And Pascal is not "better" than C, it is not a high level language.
Funny as someone that started coded back in the day Assembly was enterprise coding, my understanding of a high level language is a bit different than yours.
You asked for desktop software without any mention of time.
The implication is that his test is a proof of C's merit.
Merit is time-sensitive, in that if software is converted to another language, that language is more profitable/efficient for that software.
Therefore, the implication is also that systems converted to C demonstrate C's merit, because it's been decades since they were actually in the language you speak of.
I wouldn't say this article is recommending that you go out and program in C full-time. Many people have learned Lisp (and are better programmers for it), but few actually use it at their day job.
My point is there are fundamental computing concepts that you can pick up by learning C. In a world of high-level, low-LOC languages you can get by without learning those concepts, but it serves your and the ecosystem's best interest to learn them.
I think the disagreement we have may stem from our notions of what constitutes "fundamental computing concepts." I rank the lambda calculus much higher than C or assembly language when it comes to that. I would say that knowing your data structures and how to analyze algorithms asymptotically is vastly more important than knowing how code is being executed at a low level.
Even for the cases where low-level code must be written, I would say we need people who know assembly language and compiler theory more than we need people who know C. There is no particularly good reason for C to be anywhere in the software stack; you can bootstrap Lisp, ML, etc. without writing any C code. We need people who know how to write optimizing compilers; those people do not need to know C, nor should they waste their time with C.
Really, the most important computing concept people need to learn is abstraction. Understanding that a program can be executed as machine code, or an interpreted IR, or just interpreting an AST, and that code can itself be used to construct higher level abstractions is more important than learning any particular language.
Except that C is all over the stack that most people work in every day, and not just way down at the level of the OS.
It's astounding to me how many of the people talking about Python, Ruby, and PHP as moments of great liberation from C appear not to realize how many of the most useful libraries in these languages are really just gentle wrappers around C libraries.
Someone needs to write that not-particularly-low-level code, and someone needs to hook it up to these miraculous high-level languages. The people who do this have always been a quieter bunch than the Pythonistas, the Rubyists, the Node-nuts, and whoever else, but damn do they know what they're doing. And they certainly don't go around talking about how C is obsolete, only for device drivers, and has nothing to do with their "stack."
> There is no particularly good reason for C to be anywhere in the software stack;
Really? Not anywhere?
Who is handling your hardware interrupts? How is your keyboard and mouse input being handled? What about your video card drivers?
Now I will grant that you can bootstrap an initial run time in assembly and place your favorite high level language4 on top of that, if you add extensions to your favorite language to better interact with HW you can do everything in a higher level language, but as it stands, LISP doesn't have built in support for doing a DMA copy from memory buffer to a USB port.
My question then becomes, why the heck bootstrap in ASM rather than C?
As you said, there is no reason you cannot bootstrap in a high level language. Operating systems were written in Lisp at one time; they had device drivers, interrupts, etc.
My point is not that C is not used, but that there is no compelling technical reason to use C anywhere. The fact that Lisp and ML do not have standardized features for low-level operations is not really much of an argument. We could add those features, and we could do so with ease (CMUCL and SBCL already have low-level pointer operations and a form of inline assembly language); the only reason we do not is that nobody has time to rewrite billions of lines of C code, or perhaps more that nobody will spend the money to do such a thing. The existence of C at various levels of the software stack is a historical artifact, primarily a result of Unix having been written in C and OSes written in other languages having been marketed poorly.
The lesson is not that C is good for writing low-level code; the lesson is that technical features are not terribly important.
I would also point out that an OS is not just about interrupt handlers and device drivers. Most of an OS is high-level code that is connected to interrupt handlers and device drivers through an interface. Even if C were the best language in the world for writing low-level code, I would still question the use of C elsewhere (imagine, as an alternative, an OS that follows the design of Emacs -- a small core written in C, the rest written in Lisp).
It doesn't (yet one example of why C isn't the best systems programming language), but the concepts of C (raw memory, pointers, flat buffers), map onto underlying concepts pretty clearly.
Now that said, a lot of other things (anything dealing with asynchronous programming) don't map onto C that well at all, and other languages do a much better job at solving some conceptual problems.
But that is why languages like LISP and Haskel are taught, so that even when one is stuck working in the C ghetto, higher level concepts and more abstract coding patterns can still be brought to bear to solve problems. :)
Raw memory, pointers, flat buffers exist in almost every systems program language, even strong typed ones.
My point was that what many developers think what are C features for systems programming, are in fact language extensions that most vendors happen to implement.
In this regard, the language is no better than any other that also requires extensions for the same purposes.
Agreed; OS kernels and firmware for embedded systems all require low-level access to hardware in a way that high-level desktop applications do not. Being able to easily reason about how C is going to use resources and be compiled down to machine code for the architecture you are using can sometimes be an important asset.
I think that the point is that even if you accept that the kernel level code and device drivers are all in C, from there, there's less and less benefit to doing userland code in C from there... you could use Lisp, Erlang, Scheme or a number of other languages for userland and service oriented code.
Although I really don't care for Unity, or Windows 8's UI's I do appreciate some of the directions they are going in terms of being able to create applications that are more abstracted in nature. I personally happen to like higher level languages/environments, and modern hardware has been able to handle them very well for years.
I do think that certain patterns and practices that people have followed need to be re-thought for parallelism, and that a thread/process per request in service oriented architectures has now been a bottleneck... but there are techniques, languages and platforms that can take us much farther without digging into a low-level platform language like C.
I agree that knowing C is helpful, so is knowing assembly... that doesn't mean even a small fraction of developers should be working with them on a daily basis. Most code is one-off line of business application code and related services. It doesn't need sheer performance, it needs to be done and in production sooner... the next thing needs to get done. You can't create software as quickly in C/Assembly as you can in Java/C# (or Python, Ruby, NodeJS).
I agree with you; in the cases you mentioned there don't seem to be any good arguments for not using a higher-level language with managed memory, properly implemented data structures, etc.
It seems like there are at least two threads of thought going on in the comments in general. One of them is, "does C have any role in any domain, and if so what is that domain?". I think that it does; software development is much wider than kernels, userland applications, and compilers, and there are fields where C and/or C++ are the right tools as things currently stand. I don't think anyone would argue that either language exists as a global optimum in any problem space, but from an engineering (rather than a theoretical purism) standpoint sometimes there are few practical alternatives. Maybe these domains are small, maybe they're unexciting, but they do exist.
The other is, "what is the point of learning C?". Maybe they want a deeper understanding of manual memory management, the concept of stack and heap storage, pointer manipulation, etc. Learning more about C to play with these concepts isn't a terrible idea, although it's not the only way to learn about these things. If nothing else, learning C and trying to implement your own parsers or data structures might be a good way to better understand why writing correct code in C that accounts for buffer overflows and string issues is so difficult, and what challenges higher-level languages face in order to overcome these flaws.
Foregoing application performance adds up to a lot of money for the likes of Google and Facebook in terms of server cost, cooling, size.
Maybe Go will displace C at Google but I imagine only when it reaches performance parity.
> I would say that knowing your data structures and how to analyze algorithms asymptotically is vastly more important than knowing how code is being executed at a low level.
Except that most modern data structure research goes deep into cache awareness (i.e. structures that respect cache lines and algorithms that prevent cache misses and avoid pipeline stalling), which requires understanding of the hardware and the instruction set.
Knowing your Big-O-stuff is a prerequisite for modern algorithm design; it does not take you anywhere new, though.
Knowing your data structures does not mean being on the cutting edge of data structures research. It does mean knowing more than just vectors, lists, and hash tables. It means choosing the right data structures for your problem -- something that can have profound effects on performance, much more so than the cache.
Yes, people should know about the machine their code is running on, because when there are no asymptotic improvements to be made, constant factors start to matter. Right now, though, people tend to choose asymptotically suboptimal data structures and algorithms. Worrying about things like pipeline stalling when an algorithmic improvement is possible is basically the definition of premature optimization.
When I read "C code" in this thread - I assume people mean C and C++ together, since they're both capable of the same low-level stuff.
The thing is, the new compilers, static analysis, JIT'ing, ... available these days for C++ makes it the best time ever to write C++ in a reliable way, and being technology that is being used in the real world, this will only improve.
There's a reason the C++ language is undergoing a lot of changes nowadays, for the better. After years of no movement at all, C++11 finally arrived, supporting features improving general reliability and memory-management (single pointers, smart pointers, auto type, ...), and C++14 is on it's way. While old programs will still work, the core language evolves and so do the generally accepted standard/best practices, that when generally accepted provide very reliable code.
I work on quite a large C++ code-base, and both our test-team and static analysis tools rarely find "programming errors". Functional bugs - sure, you still have those like you have in any program, but real end-of-the-world memory corruptions or leaks are rare to completely absent. The only tricky part I guess is threading, although analysis tools have massively improved here - and this is an issue in pretty much every language that understands threads.
The nice thing about learning C is that you get to understand what exactly is happening, and while a functional language like Haskell is very cool and can in certain situations offer massive optimizations due to it's language and runtime design, it presents you with a non-existing world. C is an "easy" way to understand low-level for as far as it's useful. I fooled around with a lot of languages, including Haskell - and knowing C gives you a much better insight in what the runtime is actually doing, because you KNOW a CPU doesn't work like that, and you're able to quickly understand it's limitations and advantages.
Another way to understand what happens +- on CPU level is implementing a simple bytecode compiler and interpreter - in any language of your choosing, but for some reason, most "real world" interpreters are implemented in C/C++.
C is easy to get right. Its also easy to get wrong.
To be honest, most holes I've seen over the years are above the level of the language and are down to the implementation or design being flawed. For example SQL injection, silly business processes, elevation flaws, bad maths etc.
> You’ll realize that Object Orientation is not the only way to architect software.
Actually, pretty much all the "good" C code I've seen is using some form of object orientation, for example using structs with function pointers, or information hiding through incomplete types and void pointers. I think the better observation is that you don't need much language support to do mostly-OOP.
That and a lot of people in those "other" languages are using language support for OOP as a bit of a mental crutch. (For example, many people working in Java or C# especially tend to write lots of indecipherable OO spaghetti.)
People who use the preprocessor heavily tend to use a fairly non-OO design.
See http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html for an interesting example of a design technique enabled by that. I also note that said technique is problematic in practice not because it isn't good - it is - but because it causes people to suffer a brain freeze.
I tend to see these as orthogonal. What does a macro do but generate more code? So shouldn't the use of macros be reducible to ordinary code? That, and you can still employ this stuff at the micro level and your chatter between compilation units or library boundaries can still be OO.
In my experience, people who like to use the preprocessor come up with very non-OO abstractions. Similarly people who program heavily using templates in C++ tend not to use a lot of the OO features there either.
I may be more aware of this than you because my design sensibilities by nature are not particularly OO. This is not to say that I can't produce and understand OO designs. I both can and do, particularly if I have to cooperate with people who expect that. But given the choice, I'm more likely to head in a different direction. (A dictionary full of closures can be surprisingly useful...)
I guess I don't see a strong distinction (or see them on the same axis) because I like the preprocessor and use it when I feel it's useful, but I still write fairly OOP-like public interfaces to my code.
I guess I'm not sure what you mean by "fairly OOP-like public interfaces".
My strong suspicion is that you're referring to features that were standard in imperative programs prior to OOP becoming popular. For instance structs in C are functionally equivalent to records in Pascal which date back at least to ALGOL W in 1966. By contrast the earliest OO language is Simula 67 which came out a year later.
If so, then I disagree with you about what "OOP-like" means.
I first learned about the value of information hiding, etc, from Code Complete. The first edition of which was published before OO programming had become mainstream, and therefore says not a word about OO. That said, the ideas in that book translate well into an OO world. (And the second edition does talk about OO concepts.)
If the same ideas of OOP have been around longer than the term itself (and I do believe you are right in pointing this out), do they cease to be the same ideas? This to me is degrading into a "tomato, tomato" discussion.
Reminds me of arguments I used to get into with a friend. My friend was really into naming patterns and stuff. I really disliked that, and thought to give it a technobabble-ish name distances the practice from the concept itself, which is usually more straightforward than the name suggests. I don't think your comment is the first thing I've read that steers me in the direction of "OOP as a buzzwordy name for preexisting, good, clean practices".
> So shouldn't the use of macros be reducible to ordinary code?
No, because it's a matter of performance. To avoid code duplication, without macros, you use routines. To get the same performance as with macros the compiler needs to inline them - which only works up to a certain point. If you can't compromise on performance (for example for HPC or low power purposes) you can't replace macros/templates with anything but copy pasting code.
I think you misinterpreted my comment, but that's OK. My comment was that OOP in C can be seen kind of like a question of API or ABI (a bit like COM in the Windows world). If you need to do what some would consider hacky things with macros, or stuff that is "not very OO", you still want to keep boundaries between compilation units and libraries clean, and OO-style constructs is a good way to get that done. The fact that you used a macro is an implementation detail that disappears once your code is compiled.
However to your (to my eyes entirely tangential) comment about subrountines.. No, you can't do everything macros do in a subroutine. For instance you can't take the parameters and stringify them with #, you can't concatenate tokens with ##, you can't do funny things with braces or have a macro declare a bunch of static variables or code for you. You can't do the co-routine hack that btilly's link references (although it is very "out there"). This means you can do lots of interesting things with macros that you cannot with a function. These things can be abused but they can also make your code a lot simpler, shorter, easier to understand - and with the uglier parts constrained to a small amount of code. I don't see it as in conflict with OOP because it doesn't have to leak outside a single compilation unit or library.
> For example, many people working in Java or C# especially tend to write lots of indecipherable OO spaghetti.
I would contend that there is nothing OO about the spaghetti they right and you can write spaghetti in any language.
But I tend to agree it probably is easier to create spaghetti using OO languages.
My take why this is comes down to the fact, to do OO correctly needs a hell of a lot of up front OOD (i.e. don't start coding until you've done you OOD).
Most OO places I've worked do next to no upfront OOD before starting to hack out the code. It's feels more like an OOD on the run development model.
What you really want to say is not "learn C", but "learn computer architecture, algorithms and programming language semantics", C just happened to be the most convenient medium for this for a long time, but today there are perhaps better choices, like Go and I really hope C will finally go away one day, while people will still have to understand things like indirect addressing, hashing, pass-by-value vs. pass-by-reference an so on and so forth.
Learn Delphi, Free Pascal, Modula-2, Ada, Oberon(-2),... and see how it is possible to have down to the metal strong typed languages with native compilers.
Then understand that C and C++ ubiquity is an historical accident due to the way UNIX spread across the industry.
I can't say you couldn't have written UNIX in Algol 68, but C was very specifically developed by K&R for building the underpinnings of UNIX. They didn't just "pick" C out of a pool of available languages- C was made for UNIX.
(This is probably a gross oversimplification- please don't hang me out to dry for it- but it summarizes my understanding of the origins of C)
I suppose I'm descending to semantics and quibbling over meaningless details at this point, but I was just taking issue with the idea that C wound up in its current position on accident. It was not by chance that C makes up the underpinnings of UNIX, nor did (to my knowledge) the spread of UNIX have much to do with chance.
I don't mean to contend there are no other languages that could have been used.
While I certainly agree that understanding the "how" will give you a better appreciation of the "what" and a more thorough understanding of the "why" behind many languages (I was one of the obnoxiously vocal detractors when American universities overwhelmingly moved from C/C++ to Java), I think this goes a little far:
When you internalize these lessons, your approach to programming will completely change.
You can know which parts of a language are heavier without knowing how they're implemented. Granted, this is certainly not the same, but in a practical sense it is certainly close. Your approach to programming will only "completely change" if you've been doing things with absolutely no understanding of the performance impact of the choices you make.
There are certainly people in that situation, but anyone who has had to do any profiling to find bottlenecks in code (which I would guess means most people who have been involved in professional development for more than a year or two) likely has at least an idea of which data and control structures are going to cause issues in languages they've used at length.
So yes, I agree that understanding what's going on is good... but not everyone has the time or inclination to delve into the depths of C, and there are other ways to come about a useful understanding of language internals (e.g. actually reading about a language's specific features rather than simply guessing at their implementation based on the assumption that they're written using standard C idioms).
A little off topic, but I think people need to realize that when someone says they're a programmer, all they mean is that they write code.
I know a lot of my friends (especially the ones in tech heavy cultures like Google, Facebook, Palantir, Dropbox) easily forget that when someone says "I'm a software engineer," they mean they write code. It doesn't mean they've gone through the same coursework, can reduce 3-SAT to everyday problems, form intricate algorithms, or have written their own memory allocator.
Keeping this in mind might make conversations go smoother.
There is a difference. The difference between someone who works as a programmer, who takes it just as a job but of course can be extremely good at it - just like anything else you practice a lot; and someone who is a programmer. They are lexically the same but they mean different things. The last one, beside working (or not) as a programmer, does it for the art of it. Who not necessarily learns or does something (ships) because it's needed or it provides anything else beside the joy and fulfilment of learning and understanding it. For example, at work, when you want to stop programming you open your own personal open source project and relax for an hour with it. Then you go home after 8 hours of programming and start up your IDE and carry on with your art that may or may not ever see the light of day and it makes no difference.
That's hazy territory. While I understand what you're trying to get across, there's really no point adding layers of hidden meaning and subjectivity to the term "programmer".
(non-software) engineers, lawyers, graphic designers, accountants, chemists, doctors define themselves by occupation and not some subjective non-metric of passion. Why exactly should programming be different?
I'm not arguing that programmers shouldn't be passionate about their work, or work on side projects. However, there's really no point in prevaricating over what a "Real Programmer"(tm) is, beyond the very simple working definition we have.
Because we're talking about programming here. If we were talking about music for example, the same will apply. There are singers and there are artists and there is a clear difference in a song well made and a commercial song. Even if the last one makes you more money. But for programmers there's just that one term to use. So the need to point the hidden meanings.
There are no "hidden meanings". You're making them up.
edit :
Words, like functions, work best when their meaning is simple and clear. Like functions, there's nothing wrong with combining them (e.g. "good programmer", "passionate programmer", "programming craftsman", "software composer"), but shoehorning multiple definitions into a single word will just inevitably lead to confusion.
There is a lot more to software engineering than writing code. As I see it, proficiency in software engineering includes topics such as:
1. cost efficacy
2. availability, reliability, and scalability
3. administration (system administration); operations and support; troubleshooting & crisis management (this and #2 are their own sub-field: site reliability engineering / devops)
10. data storage: databases, relational and non-relational, caching, transactions, replication, locality
11. facilities, data centers (power distribution, cooling - though that's getting more into system engineering)
12. product design, customer experience, accessibility, human factors
13. project management
I think of programming as the art of writing code. Engineering is the act of creating reliable, controllable systems -- systems that achieve their technical goals and business goals in a steady, reproducible way. Engineering is the act of balancing tradeoffs scientifically and ensuring that quality goals are effectively met.
You might call any autodidact coder a programmer. College students can be adept programmers. However, writing code is just one part of being a software engineer. I would expect senior and above level software engineers to have experience in most or all of the topics above, and I'm sure there are more that deserve to be on the list.
Engineering in the software field isn't /always/ about building super-reliable things. That is one factor that I think differentiates it from other engineering fields. Engineering in the real, physical space has safety implications that typically require a high level of rigor at minimum. If a bridge fails or a building collapses, that's catastrophic. Physical products are only useful if engineered to a high level of quality. However, software is useful across a wider spectrum of reliability: if a back-office web app used by the recruiting team has to come down for maintenance for 2 hours on Sunday, that may not be a showstopper.
Consequently, part of software engineering is understanding what level of robustness is needed to meet business goals, and building to it appropriately, with appropriate costs, and understanding the properties of the built system. Controlling the level of reliability is what makes it engineering.
To be fair, I cannot account for what someone else means when they say they're a software engineer. But this is what I mean, and I consider the field to cover a number of topics and subjects beyond programming.
I always felt shame that I knew C but didn't understand how the code works inside the CPU. Finally I got a grip of myself and got the book with the dragon on the cover, I managed to make my stupid C compiler. Turns out, it's not that hard, and doing that finally helped me understad stack and heap much better!
It also gave me the confidence to look at how bytecode based languages work -- turns out they're also not magic, and can be understood my mere mortals.
TLDR, assembly and compilers can be understood, and it'd fun too!
How does a musician without any formal CS education and a admitted lack of understanding of some very fundamental software things, such as pointers and memory, land a San Francisco dev job? I thought those jobs were in very high demand
I'd replace 'good at programming' with 'proven ability to ship'. Most of the time it's values way over a decent codebase from what I can see. Which is often fair enough!
I was in a similar situation to the author: largely self-taught, very little formal training or knowledge of the "big picture" ideas.
It's a bit like learning a language. You can learn a foreign language without formally studying grammar, and most of the time you will instinctively get things right, and have an intuitive idea of how grammar works.
But formally studying the grammar of a new language makes learning much faster, and you have a deeper understanding.
As a person with a masters in music, a bachelor in film, and now programming for a living, I def. believe that having a persistant interest in learning about those "fundamental software concepts" is what makes such a gig achievable, especially if you keep doing the extra work in your spare time (like taking Dan Grossman's unbelievable Programming Languages class or going through Zed's LCTHW).
Given that you have a masters degree in music I would wager it would take me a very long time to get to your level in playing, writing and understanding music. It's doable of course, but I would have a lot of learning and work ahead of me. I think the same would apply to you catching up to someone having a masters degree in computer science or related fields.
I don't have a high opinion of my musical abilities :), but I agree that catching-up is both a doable and daunting process.
But, finding niches of interest to focus on usually helps, as it does when crafting really good songs in a specific style, one that matches your musical abilities and understanding. You may not have the chops, but you can still create amazing work.
With programming, I have the issue of wanting to catch up on everything and do side-projects (eventually, I'll run through this class => http://faculty.cs.byu.edu/~jay/courses/2012/fall/330/course/...), but I have found success in trying to pick-up things in conjunction with a task at hand. If I have to build a web service, I'll start that research simultaneously. Starting IOS work... then spend time with C, understand Objective-C's runtime, read about the history (and play around with Smalltalk). This piece-meal approach seems to make the jump more "doable" in my opinion.
I think that people without a CS degree can obtain a good, challenging gig if they have a good niche to school themselves in, and of course, pick-up the gaps from the people they work along with who have that background/knowledge.
Please please PUH-LEASE read "The C Programming Language" if you're going to learn C. It is THE most important programming book I've ever read. No other book comes close to concisely and elegantly describing a language.
I started programming for iOS via the same route, playing around with Objective-C in Xcode, but have since learned C. I have found that an understanding of C proves to be essential if I try to do anything reasonably complex (e.g. https://github.com/conradev/BlockTypeDescription).
I have also found that another area in which newer developers fall short is understanding how Xcode works. Those familiar with interpreted languages do not have to compile their code. While they may understand the concept of 'modules', they don't know the difference between static and dynamic libraries, what 'linking' is, and how the compiler finds header files. Someone not knowledgeable of how this works will come upon innumerable headaches down the road, especially trying to integrate third party libraries.
I would suggest a supplementary post entitled "Learn How Xcode Works, You Cheater"
Might could do that! Actually one of the biggest mysteries to me for a while was how header files worked, how the compiler finds symbols, build dependencies, linking libs, etc. Having to mess around with Makefiles helps you digest those things, but then Xcode treats them in an entirely different way. #include is a complex beast
There exist proof and verification tools for C, like ACSL and Frama-C, [1] or LCL and Splint. [2,3] Not to mention the myriad of static and dynamic analysis tools. You can prove that a piece of C code does or doesn't contain certain bugs -- this is not the case for higher-level languages (except perhaps Haskell and ML). That is why C is used for highly sensitive projects like avionics.
I have to totally agree with this. I have almost completed Learn Python The Hard Way and it has been very good to me. I have been programming in many different languages while in school (I just graduated this May, lucky me...). I must say that this might be the most complete way that I have seen to learn a new language. I am definitely doing Learn C The Hard Way and I am definitely going to donate/pay for these materials. They are extremely beneficial to any programmer even if you know all of the information.
While I agree that all programmers should learn how computers and compilers work. Learning C would just be a mean to that end. You could easily replace "Learn C" with "Learn Assembly" in this post.
I think these type of posts reinforces the over-emphasis on languages, frameworks, and tools in general we have in this industry. People restrict themselves into camps of certain tools and then use that specific tool as a general purpose tool for all problems they face in a sort of nationalistic way. And then go on the internet and start arguing over which over-used hammer is better, so to speak. Now, what is worse is that newcomers to programming quickly adopt this attitude which makes it even harder for them to learn the right things.
The other day I made a trip to the Academy for Software engineering NYC[1] and it was a great experience watching kids learn how to program. They were using Python to learn. However, I was really disappointed when a few kids expressed interest in learning Foo language because someone told them that Foo was the best language ever! I told them that after learning how to compute, they can go on and learn all the languages they want to learn and even create their own.
I agree with the original poster. Learning C definitely allowed me to understand (and feel) the code from the inside. If you just use a Hashmap or Array without knowing how you'd do it in C, you're just playing with Lego pieces. (I also agree with his view on C++ but I won't poke that hornet nest)
Thanks for this, I'm going to work my way through Learn C the Hard Way. I started on Java, but now I use a lot of Ruby and Python, and both of those languages' original/main implementations are both written in C, so I want to learn how C works.
There is no doubt that learning c & assembly language, help programmer to understand higher level languages better, even though they will not use c or assembly in their real work.
Somehow I thought that C is usually in the curriculum of any CS oriented university / college program, so most have at at least rudimentary knowledge of C.
Very interesting thread. I moved to SV a year ago and my perspective on how modern programmers think has changed enormously.
As a background, I am a software engineer on route to being a cpu architect. My job is to understand how hardware works and what changes need to go into the instruction set to allow modern software work better. I have some thoughts to share.
I also think that a lot of folks in HN are true software engineers with little hardware background. So, most arguments simply gloss over why (or why not) use C.
Let us all be very clear. C is not a great language for app development. This comes from a person who has worked his entire life with C. I have no qualms in saying this.
C is primarily just an abstraction over assembly (not the same as machine). With this in mind, you can safely assume C to be a "stateful" language. By "stateful" I mean, each statement gets "executed" and the state of the CPU and memory changes. The fact that multiple assembly instructions can get produced per-line of C is what makes it better than lower languages.
That is all that is there in C. Everything else is an add-on. The standard library functions (strlen(), printf() etc.) are all essentially a few assembly instructions clubbed together.
Now, as it turns out, oop and other paradigms were created for the sole purpose of making it easy to program. In other words, we want to lower the barrier of entry into programming and have more programmers do things that they would normally never be able to do. We were ready to take a performance penalty with higher level languages so that more people can make useful stuff with a computer.
For example, oop was made to create the illusion that a program really is objects interacting with each other or functional execution. However, folks well versed with the computer know that oop is eventually executed sequentially.
The whole eco-system of web and app developers is able to thrive because they do not have to deal with 'nasty' (I personally find them amazing) issues of why things work the way they do. Let's just say that programming is becoming commoditized and the barrier to programming is made lower by them not having to deal with these issues. If we were still programming in C, most programmers would have dropped out of their CS classes when they were freshmen.
An analogy would be you don't need to understand the internals of a combustion engine to drive a car.
So, should everyone learn C? As someone who cares about expanding the powers of a computer, I do not think wasting resources on it is worthwhile. There are enough people maintaining C and using it for great purposes. Commodity programming (application level) should not involve C as far as possible. Cpus are fast enough to handle bloatware languages. I would personally prefer people thinking of newer languages/paradigms that would expand on what people can do with a computer.
As a programmer, you do not need to learn it. It is certainly helpful and I would definitely encourage folks to try to understand it, if you are curious. But no point wasting your time on it if all you are going to do is application level development.
Now, if you are working on something really deep and involved, the story changes completely. For example, folks working on router/switch programs, fast search engines, OS, devices, simulations (basically everything cool in my biased mind) need to understand it.
An analogy is that an you do not need to understand nitty-gritty details about engines unless you are building something in the range of a Ferrari.
> You’ll realize that Object Orientation is not the only way to architect software.
I don't think C is really the way to learn this lesson - try a functional programming language to really get a feel for an entirely different programming paradigm.
(Excerpted from: Peter Seibel. Coders at Work: Reflections on the Craft of Programming (Kindle Location 6269). Kindle Edition: http://www.amazon.com/Coders-Work-Reflections-Craft-Programm... )
Seibel: When do you think was the last time that you programmed?
Allen: Oh, it was quite a while ago. I kind of stopped when C came out. That was a big blow. We were making so much good progress on optimizations and transformations. We were getting rid of just one nice problem after another. When C came out, at one of the SIGPLAN compiler conferences, there was a debate between Steve Johnson from Bell Labs, who was supporting C, and one of our people, Bill Harrison, who was working on a project that I had at that time supporting automatic optimization...The nubbin of the debate was Steve's defense of not having to build optimizers anymore because the programmer would take care of it. That it was really a programmer's issue....
Seibel: Do you think C is a reasonable language if they had restricted its use to operating-system kernels?
Allen: Oh, yeah. That would have been fine. And, in fact, you need to have something like that, something where experts can really fine-tune without big bottlenecks because those are key problems to solve. By 1960, we had a long list of amazing languages: Lisp, APL, Fortran, COBOL, Algol 60. These are higher-level than C. We have seriously regressed, since C developed. C has destroyed our ability to advance the state of the art in automatic optimization, automatic parallelization, automatic mapping of a high-level language to the machine. This is one of the reasons compilers are ... basically not taught much anymore in the colleges and universities.