Learn C
medium.com
medium.com
(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.
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?
http://www-03.ibm.com/ibm/history/witexhibit/wit_hall_allen....
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"
http://book.realworldhaskell.org/read/profiling-and-optimiza...
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)
http://www.tiobe.com/index.php/content/paperinfo/tpci/index....
C still remains the only accessible low level language to do systems programming. C compilers have been optimizing for long.
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.
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.
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.
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.
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.
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.
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.
Write yourself scheme in 48 hours (with haskell). Great learning experiance!!
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.
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.
Is there something special in clojure 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.
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.
You'll learn to feel every line of code you write
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.
It's the same with C.
I hate rearranging the furniture; it gives no satisfaction.
Satisfaction is a big part of quality in your life.
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).
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.
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?
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).
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.
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).
Where in the ANSI/ISO C standard is this support described?
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. :)
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.
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."
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.
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.
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++.
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).
Bjarne Stroustrup
http://www.stroustrup.com/bs_faq.html#really-say-that
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.
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 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.
The original version of Skype was done in Delphi.
The first versions of Mac OS were done in Apple Pascal.
Photoshop was originally done in Apple Pascal.
You asked for desktop software without any mention of time.
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.
UNIX's success made people want to port UNIX's tooling for their home computers, this lead to the spread of C implementations outside UNIX.
Had UNIX been written in language XYZ, the article would be called "Learn XYZ". Merit is relative.
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++.
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.
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++.
http://www.kalzumeus.com/2006/06/28/the-sorrows-of-java-prin...
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".
On the desktop side, you have C++/CX which is C++ with some language extensions to make talking to COM easier.
For those that would rather use plain ISO C++, there is the Windows Runtime template framework.
.NET code is JITed or compiled AOT with NGEN and makes use of CCW to interop with WinRT.
http://msdn.microsoft.com/de-de/magazine/jj651569.aspx
On the mobile side, Windows Phone 8 only has native applications, even .NET gets compiled to native code.
http://channel9.msdn.com/Shows/Going+Deep/Mani-Ramaswamy-and...
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.
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.
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.
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.
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).
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.
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].
[1] - http://www.nrc.gov/reading-rm/doc-collections/nuregs/contrac...
[2] - http://www.jsf.mil/downloads/down_documentation.htm
[3] - http://compass.informatik.rwth-aachen.de/ws-slides/havelund....
[4] - http://www.pcworld.com/article/260883/tesla_cto_talks_model_...
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.
Curious though, in what would you implement the examples I gave?
And promptly blew up the rocket.
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.
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.
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! :)
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.
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.
Integer overflows are exactly the same in Java and C# as they are in C.
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.
[1] http://blog.llvm.org/2011/05/what-every-c-programmer-should-...
"It is nonetheless supremely ironic that the demise of Lisp at JPL was ultimately due in no small measure to the unreliability of a C program."
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.
[6] Fire Safety and Building Security Systems? Yes
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.
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.
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++.
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.)
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 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...)
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.)
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".
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.
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.
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.
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.
Lets say UNIX used PL/I or Algol 68, the article would be called "Learn PL/I" or "Learn Algol 68".
(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)
There is hardly any feature in the language that makes it better than other higher level languages for systems programming.
Please note that I am older than C, for me higher level language is anything higher than Assembly.
I don't mean to contend there are no other languages that could have been used.
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).
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.
How is this an inaccurate or misleading statement? If they write code for a living, they're programmers.
> A little off topic
IMO that's an understatement.
(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.
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.
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)
4. security: risk analysis, threat modeling, cryptography, access control, vulnerability management, incident response (another sub-field)
5. computing science: algorithms, data structures
6. networks, distributed systems, load balancing
7. programming: languages, compilers, VMs, frameworks
8. quality assurance, testing
9. application architecture
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.
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!
<rimshot>
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.
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.
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"
I would say: learn C and high-level languages.
[1] http://frama-c.com/acsl.html
[2] www.hpl.hp.com/techreports/Compaq-DEC/SRC-RR-74.pdf
Any criticisms for improvements?
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.
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.
Just my thoughts.
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.