Hacker News new | past | comments | ask | show | jobs | submit login

I'm deeply conflicted about this article because I agree with many of its premises. For instance: that C is superior to full-blown C++, that object-oriented programming is no panacea, that simplicity is good.

I have serious concerns, however, especially with the first page and the first few chapters.

- They support the biases of the myopic programmer who believes that now he or she knows C, they know everything one must know about programming. I know that isn't the entire point, but you can get that from the article and I have met such programmers. You don't want to work with them, even on projects written in C.

- The "C Craft" section largely describes hacks to work around shortcomings in the syntax or semantics of C.

- The languages used for "vs" comparison are: FORTRAN, C++, Java. Fish in a barrel, anyone? Haskell, APL & J are presented as curios. Python is only mentioned in passing, as an inferior choice to Haskell for rapid prototyping of mathematically-oriented code.

- Go is presented as the "better C", which is encouraging but I'd feel more encouraged if the author showed they were properly familiar with some additional modern programming languages and the cases in which one might use them.

- The assertion that "you can write object-oriented code in C" is accurate, although I think a better point to stress is "you can write mostly-well-modularised code in C, and that's what you want a lot of the time."

- The author also ignores the reality that object-oriented C really only scales up to a certain amount of object-orientatedness, and then it becomes very unwieldly if you are not very careful. Unwieldy at a scale where using a small subset of C++ (ie "C with classes") would remove the overhead, improve the code's signal-to-noise ratio, and still not bring in most of the "bad C++" that the author is talking about.

- The author seems to have chosen to define certain terms as they see fit. For instance, simplicity is defined in terms of brevity & terseness but the example used to prove the point is that Eiffel requires "character" and "integer" whereas C only requires "char" and "int".

For an alternative point of view on what constitutes "brevity" and "simplicity", see the common C idioms for filtering or mapping any variable sized data structure. The only time it becomes less brief is if you rewrite it in C++ w/ STL or Boost. ;)

- It's also telling that in Chapter 2 the Fibonacci counterpoint to Java is in Haskell, not C. That's because a full C program would look pretty similar to the Java program quoted, albeit without the sore-thumb of wrapping it all in a class .

Anyhow, I should quit ranting but IMHO (a) you should know C, (b) you should respect C but (c) you should know some other languages and use C only when you actually need to.

(c) may not apply if you're a super-whizz genius C programmer, some of those people seem like they can carry off ridiculous use cases without making horrible messes. Most of us are not those people. ;)

"that C is superior to full-blown C++[...]"

I disagree that C is superior to C++ for most projects.

First of all, C++ offers higher-level semantics which leads to an increase in productivity. According to [1], the ratio of C++ to C LOC is 1 to 1-2.5, but I'd be interested to read other studies or articles. My experience and [1] also contradicts your statement that rewriting code with STL/Boost will lead to increased code size. It's almost impossible for C++ to be more verbose than C - consider that you can write C-like code directly in C++.

Second of all, for a developer that has good knowledge of both C and C++, writing quality C is harder. C is very prone to programmer errors, much more so than C++ where you can choose to use libraries/language features that completely eliminate some of these errors. e.g: scope-based destruction, the STL data structures, string classes, etc.

Third of all, when discussing C++ many try to make C++ look as a frightening monster ("full-blown C++"?) where you have template meta-programming interacting with automatic conversions and operator overloading and all the other features in the worst possible way. This is not much different to claiming C is bad because you can use macros and void* for everything. The languages should be compared by real-world use patterns, not dreamed up criteria.

[1] Estimating Software Costs (Jones 1998) and Software Cost Estimation with Cocomo II (Boehm 2000)

"[...]that object-oriented programming is no panacea[...]"

While it is true that some have argued for OOP as panacea, this is mostly a strawman. OOP is one possible solution that works most of the time.

> First of all, C++ offers higher-level semantics which leads to an increase in productivity.

Strongly disagree. The full C++ spec, templates and all is pretty complicated. I am sure you can squeeze out less LOC out of it, but then why not just use APL.

> Second of all, for a developer that has good knowledge of both C and C++.

I think there are very few people who know C++ well. And by know I mean they know all of its aspects equally well. Now there are plenty of people who _think_ they know C++, but don't or just know just some parts of it well. I can easier trust someone who says they 'know C', because it is a fairly short spec, not so with C++.

If you imagine a team of developers. If all of them are true C++, experts, then everything is fine. But I have never seen that. So one developer likes templates, another likes some other part of C++, and they start using that and eventually they all write C++ but they can't all necessarily read and understand each others' code. And here is where another 50 pages of C++ style guide comes in to help. But if a language needs 50 pages of custrom style guides to be useful, there is probably something wrong with that language.

> It's almost impossible for C++ to be more verbose than C - consider that you can write C-like code directly in C++.

I think it is a false dichotomy. I know the original article compared both head to head, your point picked it up, but in general it should'be be between C and C++ only. It should be C++ vs C+Python or C vs Go and so on. In other words comparing lines of code by presenting a somewhat artificial constraint is not that representative of the real world.

Templates again... Have you used them? In my current project we've used data structure and algorithm templates from the QTL (similar to STL) instead of inventing our own buggy versions.

Then we've used templates to stream arbitrary data-types into an IPC socket.

Finally, we've also used templates to create a generic repository class and to create a specialized compare function for multiple types of containers.

All of these resulted in lesser lines of code without complicating the code base. This kind of template code is nothing fancy and brings real benefits. Now it's your turn to tell me how templates have complicated your projects. Please use real-world examples.

By the way, we're not all true C++ experts in the team and yes, some of us prefer different coding styles. You know what we did? At the beginning we created a coding guidelines/standards document that outlines what is acceptable to use in the project. Problem solved. What you describe - "can't all necessarily read and understand each others' code" - is a dysfunctional team and a management failure.

"it should'be be between C and C++ only"

Ok, we can compare Python + C++ with Python + C, but C++ wins there too. e.g: PyQt/PySide.

> Templates again... Have you used them?

Not much and I have nothing against templates. Just used them as an example of C++ features. It could have been any one of: RTTI, nested classes, smart pointers, the rules of inheritance and access control, friends, exceptions, operator overloading, streams and so on. All of this is well described but in about 1000 pages in Stroustrup's book.

> At the beginning we created a coding guidelines/standards document that outlines what is acceptable to use in the project. Problem solved.

Well that was actually one of my points. If you need a 50 page language style guide, then I would argue there is something wrong with the language. The whole K&R book is just a couple of hundred pages.

That is why I would believe someone who says "I know C" vs someone who says "I know C++".

I guess I just don't see the advantage of learning the "++" part of C++ vis-a-vis the resulting increase in readability/productivity.

> Ok, we can compare Python + C++ with Python + C, but C++ wins there too. e.g: PyQt/PySide.

Well, maybe. Most Python extensions are still written in C. Python itself has a native C API. There is the ctypes library. For every Python & C++ library integration there are hundreds of Python modules with their performance critical parts written in C. The reason PySide is so nice is because they were able to hide the C++ part very well behind Python. It is certainly a development success story, but what I had in mind was the process of implementing the prototype in Python, then finding the performance critical parts and re-writing them in C.

LOC means nothing, and if you want to generate subtle programmer errors, then templates is definitely the way to go.

LOC means a lot when it comes to:

* reading and trying to understand source code

* maintaining source code

* typing and programming-related injuries

The dynamic-typed camp argues that even declaring a variable is a pain. Conciseness is one of the favourite features of JS/Ruby/Python developers and prolixity is universaly loathed in Java.

Please expand on your assertion that subtle programming errors are caused by templates. I'm interested especially in errors as a consequence of using templates from the STL or to build generic code. i.e: not metaprogramming

> reading and trying to understand source code ... maintaining source code

I think it helps but in general those things are not related very well. For examples guess what this line of code does (this is APL) ?

    X[⍋X+.≠' ';]
According to APL's Wikipedia entry it "sorts a word list stored in matrix X according to word length". It is just 1 line of code so it wins there. But now imagine reading code like that and maintaining it.

It's silly to expect to be able to understand text in a foreign language. If you want to read APL, learn APL; It's a great language.

An extreme example doesn't prove much and there are many languages that successfully balance readability with LOC. e.g: Python, JS.

Right, I was just trying to highlight that a simple metric of LOCs is not enough. One can right cryptic code to minimize LOCs but that usually leads in harder to read and maintain code.

"if you want to generate subtle programmer errors, then templates is definitely the way to go."

Please indicate how so. I cannot think of ways that make templates more prone to programmer error than, let's say, str_xxx functions for which the programmer needs to allocate extra room for a \0 (or not, depending on which function you use...). Those types of C idiosyncrasies cause much more mistakes than any inadvertent template overload ever could.

agreed on str...(), but this is not semantic, is broken lib that is hard to update for backward compatibility issues, so in some way it is not a matter of the language.

Fair enough, but I'm still interested in examples of subtle programmer errors with templates.

Judging by his blog (http://benlynn.blogspot.com/) it looks like he has considerable affection for many languages beyond C. And I think you may have misinterpreted his comparison with Fortran: rather than showing how handily C beats Fortran (fish in a barrel), he seems to be saying that even with some C99 improvements, there still are places where Fortran has the advantage (refreshingly heretical). It's definitely not a piece for beginners, but I think it may be a more balanced picture than you present.

Yeah, you're right about Fortran, my mistake. I actually skipped that chapter because I've never written Fortran. I did read the other chapters, paying particular attention to languages I've used at least a bit (Haskell, Java, C++ from that list.)

Like I said also, I agree with a lot of the premises. I just think the essay is overly positioned as "C is the best hammer" when a better essay might be "Use the right tool, C is a powerful tool. Here is how to use C like a craftsman, here are some good ways to use C you might not have thought of."

It's definitely not a piece for beginners

Who is it for? (I mean this in the most respectful way possible, I'm actually not sure.)

That's certainly a fair question. I think he probably wrote it mostly for himself: a CS graduate who fell hard for some modern languages and then later realized that neither OO or functional has all the answers. Like someone raised in a strict religious household who's always had his doubts about the faith, he finally feels confident in expressing his true feelings, and maybe gets a little carried away. I like it though.

Also, I didn't mean to suggest the author is necessarily a myopic programmer who believes that now he or she knows C... - just that the way this essay is positioned, I see it as appealing strongly but superficially to such programmers.

>that C is superior to full-blown C++

Couldn't disagree more. C++ has a much better type system than C. For many C++ programmers (myself among them) C++ was less about OO and more about giving C programmers the ability to create new types that have the powers of the built in types. I can have strings with proper string schematics instead of an array of chars that is null terminated by convention (i.e. can't be type enforced).

That's indeed a great feature of C++. And there are more great features (auto-destructors/RAII, better "const", parameterized types).

But I find other features/interactions in C++ are unnecessary and even harmful (inheritance and virtuals, typedef of references, C++'s useless implementation of checked exceptions). Templates are implemented pretty badly (Haskell's type-classes a.k.a the discarded "Concepts" could have been used to reduce the auto-generated code duplication). The "rule of three" (Copy constructors, assignment, destructors) is not enforced by the compiler and is a great error-prone hole.

C++ exceptions are problematic, and I actually prefer C's lack of mechanism, where it is completely clear (as long as nobody uses "longjmp") what the control flow is, from simple static analysis or code review. In C++, you have to keep all of the code exception-safe, but due to interaction with external libraries, it can be tough and even error-prone. Cleanup order is sometimes very important and also implicit when using exceptions, making review of its correctness much harder.

Good points. I would say that it's better to have too much, so long as I can ignore the bad parts (e.g. checked exceptions) than not enough as in C.

I also disagree about exceptions. It does make control flow trickier to follow, but the problem with C is that to really have all failure cases covered you have to put every single function in an if statement. Anything and everything can fail.

> Anything and everything can fail.

In my experience this is only true until you switch to a style where memory allocations (which are used in "anything and everything") are given to functions as arguments (from the top) rather than via malloc or such.

When allocations are given as arguments, the main reason for errors/failures disappears and a blissful ripple effect of failure-returning -> void-returning functions usually results.

It's probably worth reading the Preface.

Solution: C#

Applications are open for YC Summer 2019

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