Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
How to Get Fired Using Switch Statements and Statement Expressions (robertelder.org)
237 points by mirceasoaica on Oct 28, 2016 | hide | past | favorite | 41 comments


Anyone who rates themselves a 8-9 in C/C++ either is a compiler developer or hasn't spent enough time with the language.

It's always a fun experiment in Dunning-Kruger to see someone ranks themselves with C/C++.


Having worked close to a few highly skilled C/C++ developers (the author of HAProxy, core Firefox developers, people who write highly sensitive crypto code, ...), it is amusing to see them constantly doubt their knowledge of the language they master so well.

A decade and a half ago, one of my professor once told me: "You don't learn to master Linux, you learn to accept that you can't master it." Same point, different context.


Their perpetual self-doubt is probably a component of their mastery. If they assumed they were right after a point they would stop learning.


It's not so much doubt, but knowing enough to know there is so much you will not ever know without looking something up. C++ is a large language with a lot of dark corners. People who use it day in and day out know these dark corners exist. Even more so if they are working on a code base that many people have touched over many years.


Anyone who gives themselves a combined C/C++ rating has't spent enough time with either language. :)


I work as a full time C++ developer and the stuff in this article is just arcane magic to me. I feel like there's a level far above what anyone normally works with, and I'm an engine programmer for game dev, so it's pretty close to the metal already.


Kind of like interviewing at Google: "oh, you're a 9 in C++? let me introduce you to your interviewers for the day: Hans Boehm, Chandler Carruth, Richard Smith, and Jeffrey Yasskin. We were lucky to get them; they're off to the ISO C++ standards committee meeting tomorrow"


This would be a moronic interviewing technique, but it would also be unsurprising for Google.


I used to know some people on that committee back in the 90s.

That they knew far from the whole language taught me much about the world and my place in it.


Those guys are like Congressmen - that's a different gig form being a beat cop.


Modulo C++, if you are in the right chair, I figure making a solid six takes less than a year and that's enough to do some heavy lifting. But it's hard to find a job where you'll get the right stimulus.

I'd back off on "compiler developer" - that's severely different from "compiler exploiter."

The way to avid all the ugly in the language is to have good habits. You only use the parts that work well. When I see things like Heartbleed, I think "poor guy never debugged a comms protocol in the wild in his life." That's one of those thing that's like combat - you have to defend a real product in the wild for a span of time before you "get it."


I think elite developers rate themselves 1-10 depending on which part of language are they using and pushing forward. And Scala brought this to the world of Java as well, no chance for a single person to understand it completely.


Or perhaps they are simply using a different scale than you are. It's not like there's an objective meaning to attach to each number.


Seems to have gone offline due to the HN hug of death. Anyone got a mirror?

Edit: oh wow, I feel like an atheist who previously thought the conversation about how horrible Hell is was mostly just overwrought fanatics but has now caught a glimpse of Cocytus.


Update: Moved about 7 small images and css into S3 and page load time is now < 3 seconds with 380 users on site. I'm about 90% sure that my efforts caused the improvement.

It's still up, but it's super slow with > 20-60 second page load times. I just moved some images into s3 which made it a bit faster. There are currently 267 people on the site according to google analytics.


Multiply google analytics users by k to get a more accurate number, where k is a percentage of readers using uBlock or some other blocker that blocks google analytics. Ie k=1.5 for a tech heavy audience :)

Edit; Anecdata, almost all my signups come from users who block google analytics.


Wow.

I suggest tossing the site logo in s3 too (which timed out when I was trying to mirror the page at archive.is), along possibly with the JS.

As for the article, my brain felt a bit like it was in freefall, and continuously played sounds of glass and crockery breaking as I read. Thanks for the intellectual stretching exercises :P


The logo failed to mirror, but everything else is intact: http://archive.is/IoYJZ


I made the terrible mistake this week of using the strategies in this article as a way to provide to my employer my resignation, and unfortunately it didn't work as I'd expected.


That's because the premise of the article is completely wrong. There's a venerable tradition on Wall Street of generating unmaintainable code and not sharing your knowledge with anyone else. If you're lucky enough for the code you're writing to be mission-critical, you can write your own check and never get fired.


I won't say which, but one of my previous employers had a policy of only using frameworks and libraries that were invented at the org to reduce the likelihood of employees developing transferable skills. I learned about the policy after I wrote a detailed write-up of a specific bug class that was affecting all of our apps, and recommending switching libraries, and sent it to the leads of all of the development teams across the org. Learning this was a contributing factor in my leaving the place :/


Two question from the "hacker" variant[1] of the old usenet/gopher-era "purity test":

    00F0 Is your job secure?
    00F1 ... Do you have code to prove it?
[1] http://www.mit.edu/people/mjbauer/Purity/hackpure.html


Ah, the classic "try to get fired" move and they promote you instead!


Boy, that's just a straight shooter with upper management written all over him.


Our entire society seems to be based on Office Space and Idiocracy


The Duff's device example is incorrect. In n%4, the value of n before n=(n+3)/4 should be used, not after that.


Thanks, I modified it from an example one but introduced some mistakes. I've corrected it and tested it this time.


I am reminded of the following story, reproduced here in its entirety

----

Thompson, Ritchie and Kernighan admit that Unix was a prank

=====================================

(This piece was found on Usenet. This is fiction, not reality. Always remember that this is not true. It's really a joke, right? -- Editor)

In an announcement that has stunned the computer industry, Ken Thompson, Dennis Ritchie and Brian Kernighan admitted that the Unix operating system and C programming language created by them is an elaborate prank kept alive for over 20 years. Speaking at the recent UnixWorld Software Development Forum, Thompson revealed the following:

"In 1969, AT&T had just terminated their work with the GE/Honeywell/AT&T Multics project. Brian and I had started work with an early release of Pascal from Professor Niklaus Wirth's ETH Labs in Switzerland and we were impressed with its elegant simplicity and power. Dennis had just finished reading 'Bored of the Rings', a National Lampoon parody of the Tolkien's 'Lord of the Rings' trilogy. As a lark, we decided to do parodies of the Multics environment and Pascal. Dennis and I were responsible for the operating environment. We looked at Multics and designed the new OS to be as complex and cryptic as possible to maximize casual users' frustration levels, calling it Unix as a parody of Multics, as well as other more risque! allusions. We sold the terse command language to novitiates by telling them that it saved them typing.

Then Dennis and Brian worked on a warped version of Pascal, called 'A'. 'A' looked a lot like Pascal, but elevated the notion of the direct memory address (which Wirth had banished) to the central concept of the "pointer" as an innocuous sounding name for a truly malevolent construct. Brian must be credited with the idea of having absolutely no standard I/O specification: this ensured that at least 50% of the typical commercial program would have to be re-coded when changing hardware platforms.

Brian was also responsible for pitching this lack of I/O as a feature: it allowed us to describe the language as "truly portable". When we found others were actually creating real programs with A, we removed compulsory type-checking on function arguments. Later, we added a notion we called "casting": this allowed the programmer to treat an integer as though it were a 50kb user-defined structure. When we found that some programmers were simply not using pointers, we eliminated the ability to pass structures to functions, enforcing their use in even the simplest applications. We sold this, and many other features, as enhancements to the efficiency of the language. In this way, our prank evolved into B, BCPL, and finally C.

We stopped when we got a clean compile on the following syntax: for(;P("\n"),R-;P("|"))for(e=C;e-;P("_"+(u++/8)%2))P("| "+(u/4)%2);

At one time, we joked about selling this to the Soviets to set their computer science progress back 20 or more years.

Unfortunately, AT&T and other US corporations actually began using Unix and C. We decided we'd better keep mum, assuming it was just a passing phase. In fact, it's taken US companies over 20 years to develop enough expertise to generate useful applications using this 1960's technological parody. We are impressed with the tenacity of the general Unix and C programmer. In fact, Brian, Dennis and I have never ourselves attempted to write a commercial application in this environment.

We feel really guilty about the chaos, confusion and truly awesome programming projects that have resulted from our silly prank so long ago."

Dennis Ritchie said: "What really tore it (just when ADA was catching on), was that Bjarne Stroustrup caught onto our joke. He extended it to further parody Smalltalk. Like us, he was caught by surprise when nobody laughed. So he added multiple inheritance, virtual base classes, and later ...templates. All to no avail. So we now have compilers that can compile 100,000 lines per second, but need to process header files for 25 minutes before they get to the meat of "Hello, World".

Major Unix and C vendors and customers, including AT&T, Microsoft, Hewlett-Packard, GTE, NCR, and DEC have refused comment at this time.

Borland International, a leading vendor of object-oriented tools, including the popular Turbo Pascal and Borland C++, stated they had suspected for Windows was originally written in C++. Philippe Kahn said: "After two and a half years programming, and massive programmer burn-outs, we re-coded the whole thing in Turbo Pascal in three months. I think it's fair to say that Turbo Pascal saved our bacon". Another Borland spokesman said that they would continue to enhance their Pascal products and halt further efforts to develop C/C++.

Professor Wirth of the ETH Institute and father of the Pascal, Modula 2, and Oberon structured languages, cryptically said "P.T. Barnum was right." He had no further comments.


That's exactly what I was going to post! Haha. My comment was going to say one section on switch statements in the article should've been what they "got a clean compile on." Classic, great parody given it seems more believable over time.


[When we found that some programmers were simply not using pointers, we eliminated the ability to pass structures to functions, enforcing their use in even the simplest applications.]

I'm confused. You can pass a structure to a function by value in C. What does he mean by this?


In ANSI C, not in K&R C. https://en.wikipedia.org/wiki/C_(programming_language)#K.26R... doesn't explicitly say it, but gets close:

"In the years following the publication of K&R C, several features were added to the language [...] functions returning struct or union types (rather than pointers)"


Statement expressions are certainly not in the standard nor supported by MSVC, and based on the compiler behaviour exhibited in the article, it looks like they may have been added in haste without considering (nor testing...) how the feature would interact with all the other features of the language.

The Asm fragment there seems like it doesn't even match the C at all; it begins with these 3 rather useless instructions which appear to be a very dumb translation of "if((char)1)", a statement that does not even exist in the C code:

        movb    $1, %al
        testb   %al, %al
        jne     .LBB0_2
In the first iteration the use of the jump from the switch statement jumps over these instructions, although they are executed on later loop iterations. It seems pretty reasonable that the compiler would do this, after all you are telling it to branch into the middle of a for loop comparison.

IMHO if branching to that location is allowed, this would be a defect because there is a (slightly) saner interpretation: branch there to execute the case, then "return" 10 from the statement expression and compare that to i, continuing onward from there as usual. Whether the compiler chooses to use temporary variables shouldn't make any difference according to these semantics. If we "linearise" that example according to such a principle, it may become something like this:

        int i = 0;
        // switch(i)
        if(i == 0)
            goto case0;
        else
            goto switch_end;
        // i = 0;           // unreachable
        // goto loop_check; // unreachable
    loop_body:
        i;
        // loop increment
        i++;
    case0:
        // if there was code for case 0 it would go here
    loop_check:
        int r = 10; // result of statement expression
        if(i < r)
            goto loop_body;
    switch_end:
        return 0;
...and that does not cause any uninitialised reads or writes. Also, the extremely contorted control flow in some of these examples reminds me of continuations.

The jump into the function parameter is puzzling at first (and once again shows what I'd consider a defect since it crashes), but using the same semantics of "continue at the remainder of the statement", it can be transformed into this:

        int i = 0;
        if(i == 0)
            goto case0;
        else
            goto switch_end;
    case0:
        // if there was code for case 0 it would go here
        int r = 1;
        // continue with evaluating the parameter
        int p = i + r + i;
        // and call the function
        f(p);
    switch_end:
        return 0;


> there is a (slightly) saner interpretation: branch there to execute the case, then "return" 10 from the statement expression and compare that to i, continuing onward from there as usual [...] and that does not cause any uninitialised reads or writes

The code you wrote did one additional thing: it moved the "switch" starting point from before the "i=0" initialization to after the "i=0" initialization, which is more than just a different interpretation, it's completely different semantics.


i is initialized twice in the example code

  int i = 0;
    switch(i){
     for(i = 0; i < ({case 0:; 10;}); i++){
The compiler probably tried to be intelligent and optimized it away.

EDIT: Okay I tried reading the assembly and I think I understand whats going on:

  movl    $0, -8(%rbp)                     # translation of i = 0
  ...                                      # the following is jumped over
  movl    -8(%rbp), %eax
  movl    %eax, -16(%rbp) # 4-byte Spill   # i is moved to somewhere else in memory
  ...                                      # the switch jumps between these
  movl    -16(%rbp), %eax # 4-byte Reload  # tries to reload i from its "new" position
Whoever wrote the code to place variables into memory obviously didn't consider this kind of insane control flow.


Yep, you are right, I missed that "i" was initialized twice; when I see "i=0" in a for loop I assume it isn't initialized right above (otherwise, why put the "i=0" in the for loop at all?).


> not in the standard nor supported by MSVC

to be fair MSVC doesn't support a lot of things that are in the standard either


Statement expressions have been supported by GCC for almost two decades. Maybe more than two decades. Most C compilers support them, including clang, Sun Studio, Intel, and many others. In fact, MSVC is the only compiler I've used that doesn't support them.

As for whether they were well thought out, consider that you have the same initialization scoping problem with C99's compound literals, and more generally with any automatic-storage variables. You cannot jump over (using goto or switch) the declaration or definition statement that instantiates the variable. It's doubly stupid when you do it with statement expressions because the warning is right there in the very small, concise section of the GCC manual explaining them. And nobody should be using a construct without understanding the rules for using it, which typically means reading the rules.

You can't fix stupid.

I was actually bit by a scoping issue like this a year or two ago. I was using a compound literal in some code that a drive-by patch submitter made work with C++. Now, I'm not a C++ programmer, but I knew that C++ didn't support C99 compound literals. Yet I stupidly assumed that because GCC and clang accepted the construct syntactically (and without warning) they'd implemented the same semantics. Well, they didn't, at least not after somebody "fixed" those compilers to give that syntax the semantics of C++ temporaries. (Which made no sense to me; it's a parse error in standard C++, and subtly changing the semantics like that was bound to break code.) The difference was important, because compound literals have block-scoped lifetimes, whereas C++ temporary objects only have expression-scoped lifetimes. In short, this caused perfectly legal C code to scribble over stack memory when compiled as C++.

I must assume at least some of the blame because I should have known better than to continue using a compound literal in header code that purported to support C++. OTOH, I had zero intention of ever using that code as C++; I just thought I was doing somebody a favor by accepting their patch. No favor goes unpunished, I guess.

As for Duff's Device... I love using the Duff's Device to implement a poor man's coroutine in standard C. You can write very clean and concise code this way. For example, here's a re-entrant implementation of POSIX getopt I wrote. It's probably the shortest correct implementation of getopt in C or most any other language.

https://github.com/wahern/lunix/blob/rel-20161026/src/unix-g...


Maybe compilers shouldn't have stupid extensions that make it possible to crash/hang the compiler?


I did not know about the switch-based co-routines, but they made me groan and giggle at the same time.

I try to come up with a real-world metaphor to describe this mixture of horror and delight to non-programmers, but I am not sure there is one.


First code snippet has a bug: no colon after default.


Fixed.




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

Search: