Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

It seems to me C/C++ has always had problems. K&R C had weird stuff like char pointers used to point to anything. And modern C++ has odd complexities like what Scott's article illustrates.

Was there ever a Goldilocks moment when C was just right?



C works great, as an alternate to assembler, to bootstrap unix up on meager, 80s style, hardware.

Based on things like the shell tools and languages like awk (and other related descendants), I don't think even the unix creators meant for much application level work to be done in C, though, but by assembling components in higher level languages. Try telling that to The Management and all the macho/masochistic Real Programmers, though. Bounds checking? Memory management? (names you can identify to the left of the types, like in Algol, instead of to the right?) That's for sissies!


Worse is that even the C creators saw the danger of using C without computer assisted validation and created lint in 1979.

https://www.bell-labs.com/usr/dmr/www/chist.html

Yet to this day, many still don't use any sort of static analysis tool.


To be honest, I seldom used lint, either, when I was starting out (although I suppose I cheated by using the Borland IDE in the early 90s). However, when using gcc in the mid to late 90s, it was just too easy to tack on -Wall (enable all warnings) to the options. No real excuse not to always check things, at that point.


I'm struggling with this too... I'm implementing a shell, and on the one hand I've been looking at ancient C code in bash, dash, zsh, mksh, etc. That's clearly not the right way to do it, with raw strings, pointers, and globals everywhere. It's ridiculously verbose and error prone. All recursive parsers in C seem to use setlongjmp for error handling. They have weird memory management with stack allocated strings and globals too, because memory management in C is such a pain.

I tend to like "C with classes". When I started working at Google, the C++ style was a breath of fresh air over what I had seen in the game industry (this was in 2005, so C++ was in a very different state). It was very much C with classes: no exceptions, no iostreams, no operator overloading, no default copy constructors or assignment, in/out params, etc. (Lately it has been trending toward "modern C++", albeit with custom internal libraries for errors and such)

Then C++ 11 came out -- you really can't do without auto and range for loops. It looks like strongly typed enums are useful, and some STL stuff. For recursive parsers, exceptions instead of setlongjmp seems useful too (setlongjmp doesn't work with destructors AFAIK). I'm scared of R-Value refs and move semantics -- I don't know anything about those.

I guess my point is that it's 2016 and it's hard to know if there was a goldilocks moment. Google was using a restricted dialect of C++03 which I think was pretty great and built a lot of real software, but it's hard to say that C++11 didn't add anything useful.

I'm sure the Google style diverges pretty wildly from Bjarne's new effort of C++ core guidelines, which I need to look into more:

https://google.github.io/styleguide/cppguide.html

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppC...

It seems like the LLVM codebase really knows what it's doing in terms of C++, which makes sense, but honestly it's fairly complex for what I want to do. So I think we are just stuck with all these local dialects, which makes code reuse a problem.


I'm not quite sure what you mean by 'goldilocks moment', but I think C++11 was it. Ever since then, the language has had a nice balance of high level abstractions at low level performance. (Theoretically it actually got faster due to move semantics)


The parent was asking the goldilocks question -- was there ever a point where C++ was not too complex like modern C++, e.g. this {} issue, but had enough features (contrast with C, which doesn't have enough features for many applications). I don't think there was such a moment.

Apparently move constructors were a de-optimization in the case of std::vector. As far as I remember, it's related to iterator invalidation and move semantics making small-size optimization impossible (e.g. inlining small vectors into the object itself rather than having another pointer and heap allocation). I'm pretty sure it's in this video:

https://www.youtube.com/watch?v=vElZc6zSIXM

Although it's debatable how big a deal this is, it's a good example of the point. People like "C with classes" because they can read the source and kind of figure out what code is generated. They can reason about locality.

Although I don't consider myself an expert C++ programmer, if I can't reason about the consequences of move constructors on std::vector, which is a fundamental and relatively simple data structure, then the language is already getting into "surprising" territory. I would have never figured out that de-optimization unless I heard it in a video.

On a related note, I wish that return value optimization had better syntax -- that would make move semantics unnecessary in a lot of cases.

On the other hand, reasoning about the generated code is already a lost cause because assembly code is so complicated now. We now have to live in a world where we can never fully understand our tools.


At what point is it mentioned in the video? AFAIK small optimization on std::vector was already invalid since .swap() needed to keep existing references/iterators valid, couldn't throw or call copy constructors/assignment.

RVO being transparent would be nice, though. There's a proposal somewhere to make it guaranteed in some circumstances, but it's still fairly opaque when reading code


Sorry I don't recall offhand. It was definitely Chandler Carruth who mentioned this, and he has a handful of videos on YouTube from CppCon. They are all worth watching if you care about such things :)

I don't know the details but I'm fairly sure that the issue is that move constructors in C++11 made small size optimization impossible in some cases. I think he works on the LLVM optimizer so that would be a primary source and not hearsay.


On top of assembler being complicated, the CPUs contain another sort of compiler and optimizations, so it gets even harder to know what exactly happens.

I thought that moving is optional in a sense, and the compiler could decide to copy instead of move (?)


C was already bad when it was born, comparing with what Burroughs was doing in Burroughs B5000 in 1961, nowadays sold by Unisys ClearPath MCP. Or other similar languages on those days, like Concurrent Pascal on Solo OS (1975).

When I learned C in 1993, it seemed quite poor compared to my Turbo Pascal 6.0 type safety and respective language features.


The main advantage of C was that it allowed you to type stuff super fast comparing with Pascal ( {} instead of Begin .. End etc.) and had some very handy shortcuts for often used operations like ()?:, ++, --, += etc. Less verbose language, less need to type syntactic structures. You could basically keep the flow of what is in your mind with the progress on your keyboard and forget about typing it; you were simply assembling stuff in your mind and at a rapid face making it happen on a computer. Something similar you can now probably experience with Go, sometimes Scala.


Typing fast usually doesn't lead to working programs that solve what is actually the customer's problem.

Software engineering isn't about "keeping the flow", rather about achieving the quality, deliverables and desired outcomes required by the users of the software.


It's what prepares you best as a young person to pass interviews at companies of your dreams or win ACM ICPC and similar competitions.


None of the companies of my dreams was using C and "ACM ICPC and similar competitions" was done in Prolog.


Is this a typo for Pascal? When I did the ICPC, Prolog was not a permitted language in my region, and IIRC not at worlds either. But Pascal was (which I always found quaint, but perhaps that was my provincialism).


No, we didn't had anything like ICPC in the 90's on my home country, at least it wasn't known to us.

But we had "... similar competitions", one of them was national logic programming competitions.


:)


> The main advantage of C was that it allowed you to type stuff super fast comparing with Pascal ( {} instead of Begin .. End etc.)

Speaking as a developer who works mostly in C and C++, that's a pretty crappy advantage. Based on the answers here[1], it seems like the real benefits were a more permissive type system, better library, separate compilation units, and better ways to directly access hardware.

https://www.quora.com/Why-did-C-succeed-over-Pascal


All the advantages of C over Pascal, usually disregard the extensions that almost all Pascal implementations had.

All the points you mention from Quora were covered by Object Pascal, Turbo Pascal, Quick Pascal, TMT Pascal, Think Pascal, VMS Pascal, HP Pascal,....

Yes there were lots of dialects, but writing C code back in the day each C compiler outside UNIX had their own view of what compiling K&R C was all about, C wasn't any better in portability across compiler vendors and OSes.

If it wasn't for UNIX's adoption, C would have been just yet another systems programming language.


This was my personal experience, where learning C allowed me to make a 3D engine with Gouraud shading in a few days, where the same in Pascal would have taken a lot longer, mainly because of necessary syntactic sugar. C just allowed to go super fast and didn't restrict experimenting as much as Pascal did (which is still a pretty permissive language), and even adding inline assembly code to render fast felt natural, unlike in Turbo Pascal. And this speed carried over to competitions.


> inline assembly code to render fast felt natural, unlike in Turbo Pascal.

Turbo C:

    asm {
     ....
    }
Turbo Pascal:

    asm
     ...
    end;
What was unnatural about it?


You could do some tricks with GCC like not specifying arguments in your MOV instructions and let GCC use the optimal registers it calculates during compiling. Practical consequence was that instead of doing some default MOV AX, [something] then MOV BX, [something], then e.g. MUL BX, you could have avoided the first two operations as GCC would chain them together properly without the need to fill in values; so by inlining such code you'd get very very close to hand-written assembly language without additional overhead, speeding up your 3D engine significantly.


On those days I seldom found a compiler that was able to generate better Assembly than a human coder at junior level would be capable of.

So we just wrote the inline Assembly 100% ourselves, regardless of the compiler.


I'd say the two more important advantages were a) the bare-metal view C gave you, down to individual bytes, which was important for systems-level programming, and b) the lack of overhead from things like bounds checking and garbage collection, which was useful on the butt-slow machines in the 70s and 80s.


Turbo Pascal (from early versions) could very much handle individual bytes (and IIRC, had bit manipulation primitives like bitwise and/or/xor/not, shr, shl, etc.), and could even address memory at fixed locations, such as the video memory on the IBM PC (and segment:offset x86 memory at that). Don't know about other Pascal implementations, such as the others pjmlp has mentioned elsewhere in this thread, but would not be surprised if some of them could as well. I agree with pjmlp's statement (again, elsewhere in this thread), that C is probably being compared (to C's advantage) against early standard Pascal (which was a limited, academic language), not the commercial implementations which would have been / were more pragmatic. And I say this as a guy who liked and used both Turbo Pascal and C (C on DOS, Unix and Windows) a lot, for long, earlier, including being team lead for a successful Windows C database middleware product.


Lots of languages allowed for a) and b), including the ones I mentioned, C wasn't neither the only one nor the first one.




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

Search: