Hacker News new | ask | show | jobs
A way to torture an interviewer (C++, FizzBuzz)
63 points by jpegqs 1459 days ago

  #include <stdio.h>

  static struct X {
    void* operator new[](size_t) { return (char*)&1[""]; }
    void operator delete[](void*) { }
    X() : X((char*)this - "") { }
    X(char i) {
      printf(i%3?i%5?"%s%i\n":"%s\n":"Fizz%s\n",i%5?"":"Buzz",i);
    }
  } *x = new X[100]();

  int main(){}
16 comments

You wouldn't torture him. You would just zero the probability of getting an offer. There's no SW house or colleague in his right mind that would want a developer that writes obfuscated and needlessly complex to understand code.
I would not want developer to write this kind of code in production applications but I would very much hire a person who is capable of coming up with the code like this.
..except they probably wouldn't come up with janky code like this - especially not during the interview

This is something you memorize to try to show off

>"person who is capable of" - is not equal to actually doing it on an interview unless it was their own original code
This whole point of Fizzbuzz is to see how one structures their code. Or at least ascertain that one _can_ write code in the first place.
I could not care less about the purpose of FizzBuzz. In my other life I've interviewed many programmers and I did not get disappointed. But I would never ask them to do live coding in a first place.
How much structure can a fizzbuzz have exactly?
shudder

Sometimes I wonder why some dev teams take 10x longer to develop some functionality than what I would consider reasonable.

Then I see code like this.

  > How much structure would you like?

  top = 100

  data = { 
      3: "fizz",
      5: "buzz"
  } 


  for i in range(1, top+1):
      output_num = True
      for j in data:
          if i%j == 0:
              print(data[j], end="")
              output_num = False

      if output_num:
          print(i)
      else:
          print("")
This is enough structure to anticipate the inevitable customer changing the requirements. No magic numbers in the real code.

Of course, I just banged this out in a web browser text editor. In PyCharm that better be wrapped in a function at minimum, or a module.

You can make it easily extendable for division by 7.
Is consider this entertaining rather than torturous.

A playful response to the mind numbing idiocy of fizzbuzz.

If someone wrote that in an interview I'd be keen to get them to explain to me exactly how it works... my C++ being a bit rusty (I mean old).
Explanation:

1. There are no data members inside X, in this case the size of the structure is 1 byte.

2. main() does nothing.

3. *x = new X[100]() - this requests a new array of 100 elements of type X, at a stage before main() is called.

4. The new[] operator is overloaded in the class, this operator must return the address for the requested array. It returns the address of the empty string object plus 1.

5. For each of the 100 elements, the X() constructor is called, the "this" address for those elements will be the value returned by new[] plus an index from 0 to 99. The X() constructor converts this to a number from 1 to 100 by subtracting the address of the empty string. This is the only UB here, but it works in all major modern compilers since they combine the same strings into one instance.

> This is the only UB here.

That's debateable.

1. new[] doesn't return a pointer that is suitable for storage for the objects. Yes the objects are empty (only contain padding), but that doesn't absolve from UB.

2. "" is used at two places, assuming that they refer to the same const char array. This is optimization is allowed, commonly implemented, but not guaranteed.

3. An empty struct having 1 byte size is also implementation defined, although common ABIs specify this. It also wouldn't make sense to implement it differently.

Since new[] does not actually return an array (returns a pointer to 1-past-the last element in "" string/array) and later "this" pointer is calculated using an arithmetic operation that goes out of bounds (for elements that > 0), that would also be UB. ""+2 would be UB for example.

But maybe it is not UB because it is not calculated explicitly by the program, hard to tell

Unless they had, and i know this is hard to imagine in a c++ dev, a sense of humour
I mean the code also includes a bunch of undefined behaviors, we do not joke about that
QA engineer for a C++ compiler?
This program is undefined, so no, except maybe if you can make the compiler itself to crash.
That's a good thing to test.

Btw, here's a C++ sample that crashes icc: https://pastebin.com/PiRtZi1t. I haven't reported it because it's funnier this way.

What if the SW house is competing in the ioccc?
Fizzbuzz is a pass to the next questions. It's a way to weed out random people who have no idea about programming but for some reason came to the interview.

While this code wouldn't be an instant offer, it would be a great solution in my eyes and it would follow hardest questions to qualify a candidate for senior position.

That's my opinion at least. I'm making a hiring decisions in my company.

It's a great way to tell jokes, loosen up the interviewee, and get the jitters out.
I always felt that being annoying is an art - something that requires dedication and craftsmanship - and whoever wrote (and hopefully actually did) this is clearly a master at it.
Holy moly, this gave me a good (well needed) chuckle.
Talking about actually genial FizzBuzz interview answers, I have yet to see someone even going close to this: https://aphyr.com/posts/353-rewriting-the-technical-intervie...
Good lord, this made my morning.
Yay, let's talk about FizzBuzz!

This is the fastest PHP version I could come up with so far:

    <?php
    
    ob_start(null, 32000);
    
    $a = [0, 1, 'fizz', 3, 'buzz', 'fizz',
          6, 7, 'fizz', 'buzz', 10, 'fizz',
          12, 13, 'fizzbuzz', ''];
    
    for ($i = 1; $i < PHP_INT_MAX-15; $i+=15) {
        $a[0] = $i;
        $a[1] = $i+1;
        $a[3] = $i+3;
        $a[6] = $i+6;
        $a[7] = $i+7;
        $a[10] = $i+10;
        $a[12] = $i+12;
        $a[13] = $i+13;
        echo join("\n", $a);
    }
I'm sure there still are ways to make it faster. But I fail to think of them. Except for unrolling multiple loops into one. But that is so ugly. Any ideas of elegant ways to make it faster?

Testing the performance like this:

    php fizzbuzz.php | pv > /dev/null
215MiB/s on my slowish laptop.

The "yes" command gives me about 10x the throughoutput:

    yes fizz | pv > /dev/null
3.04GiB/s

Shows how much wiggle room there still is!

I also wrote a python version of it, but it performs 10x slower:

    a = [0, 1, 'fizz', 3, 'buzz', 'fizz',
         6, 7, 'fizz', 'buzz', 10, 'fizz',
         12, 13, 'fizzbuzz'];

    for i in range(1,1000000000,15):
        a[0] = i;
        a[1] = i+1;
        a[3] = i+3;
        a[6] = i+6;
        a[7] = i+7;
        a[10] = i+10;
        a[12] = i+12;
        a[13] = i+13;
        print("\n".join([str(x) for x in a]));
Maybe the bottleneck is the loop that converts the integers to strings? Maybe someone with Python knowledge can comment on how to approach this in Python!
https://tech.marksblogg.com/fastest-fizz-buzz.html

Not sure I'd call writing Assembly "elegant" but hey!

Yeah, I know all the different language versions from the FizzBuzz shootout on Stackoverflow.

I'm particularly interested in comparing PHP, Python and Javascript.

So I would like to write an "optimal" PHP version first. Afaik that has not been done yet.

Probably your implementation is limited by the speed PHP/echo can output things to stdout, rather than your implementation per-se.

Better, use a benchmarking framework/library to see how many OP/sec you can do, within the PHP runtime, so you remove stdout from the benchmark.

Well, that's part of the challenge. To write to stdout as fast as possible.

There is a large FizzBuzz shootout here that I like:

https://codegolf.stackexchange.com/questions/215216

I think it's a nice "standard" for FizzBuzz comparison.

Well, then remove the whole "fizzbuzz" part of the equation and just try to output as much data to stdout as possible.

Conflating the two seems to confuse more than measure anything useful.

As someone who avoids C++ these days ...

Is this a compile time FizzBuzz?

`(char*)&1[""]` is the empty string here returning its data segment address as the offset? Not sure about the purpose of `1`.

Is the iteration achieved by the constructor basically re-invoking itself?

It's a static initialization time FizzBuzz. In this case, I think it's executed before main() is called, and not at compile time.

Unless, of course, you have a very clever compiler that determines memory allocation is not actually allocating anything and that the output is a static string, and there are no side effects. Such a clever compiler could optimize it all into just one "puts" call.

Neither GCC nor Clang bake the final string into the data segment. If I had to guess, printf is the one preventing the more fancy optimizations to take place.
I think so too. Also, depending on stdlib output buffering, the external I/O behavior of 100 puts calls is potentially different from just one call.

In other words, there might be a different number of stdout write-calls.

&1[""] is the same as &(""[1])
Ah, so it's the nil address?
The address of the nil byte + 1
But isn't `""` 0 terminated? So the first offset past the nil byte is 0, interpreted as an address.
"" is empty, so ""[0] is the nil byte.

The code uses "" as an arbitrary address, and ""[1] as that address + 1.

This way this-"" gets you 1-based index into the array.

It assumes the compiler dedfuplicates strings, making the behavior of this program undefined.

No, it's the address past the end of the array {'\0'}.
Mind to unpack that for me?

Here's how I unpack this: ""[1] is the 0 (termination) byte. The 0 byte is then interpreted as an address -- the nil address.

But what's the use of asking for the address of the null terminator? Where is that stored exactly?

The "" will define a null terminated char array to represent the string. But as it string contains no text it's a char array that only requires one byte (i.e. it contains nothing but the null termination character).

Now the first character of that char array is found here: ""[0]

The second character is found here: ""[1]

So the address of the second character is found here: &""[1]

But as the string was represented by one byte char array that second address is past the end of the string.

So it's actually an undefined address.

""[1] is not the termination byte, it's the byte after that.

Its address is taken there with &, which yields a const char*. The (char *) cast is only there to cast away const.

The evilest way to write `nullptr`.
it is not nullptr, it is address past \0 in "", which is an invalid address
No, the address itself is not invalid, you're just not allowed to dereference it. Pointers have to point at a valid object or, in the case of arrays, one past the end of the array. It's what `std::end` returns
Hence, evilest. (It got me.)
I’d walk out. Never, ever take a job given to you for solving a riddle. Everyone else there will have gotten theirs the same way and it won’t be great.
I mean I would even consider fizzbuzz a riddle. It’s one of the simplest programming tasks I have ever been asked in a technical assessment. Do you have a preferred alternative?
This is undefined behavior. According to the C++ standard, there is no way to reason about what this does. Anything can happen with this code.

Once you have undefined behavior, you lose the ability to reason about your entire program.

Thus, this program does not solve the problem.

It demonstrates a lack of knowledge about undefined behavior in C++.

Rating: Absolutely would never hire this candidate.

Undefined behavior doesn't mean there is no way to reason about what the program does according to ISO C++. It means that the way to reason about it is outside of ISO C++, in specific ways, like that it may be a documented extension in the implementation or numerous other possibilities; you have to research those possibilities before concluding that there remains no way to reason about it.
Then there's 50GiB/s fizzbuzz

https://codegolf.stackexchange.com/a/236630

> } *x = new X[100]();

This C++ coder seems to have a habit of writing unecessary constructor argument lists. The example works if we change it to:

  *x = new X[100];
There are situations in C++ in which an extra constructor parameter list will do something different, so I'd be wary of this candidate.
The very point of FizzBuzz is that it is a test whether a candidate can write it straightforward enough, even redundantly, but readable — or they have to resort to some ugly cleverness :)
We no longer ask candidates to write code. Instead we give them code to review and plenty of time. After that we do a meeting to discuss the changes. Works quite well for us.
If a candidate were suggesting this as their serious FizzBuzz implementation fit for production, I'd have a hard talk with them about readability.
If an interviewer had a "hard talk" about anything during an interview, i'd have an immediate hard walk.
If I couldn't convince you to walk back and finish the interview, I'd say that was a hard balk.
Curious, why? If I'm interviewing, I like to receive feedback if I'm not good enough for the role. I also return the courtesy
What implementation of FizzBuzz do you use in your production environment?
No microservices, not nearly Enterprish enough:

https://github.com/domdavis/fizzbuzz

"FizzBuzz split into a set of 4 microservices designed to be run as a fleet of docker images for highly concurrent, highly resilient deployment."

Obviously outsourced to a 'competent' FBaaS provider!

https://fizzbuzz.ketzu.net/to/100

(Also fun when you just outsource task in a language introduction task in a leetcode-like setting and get surprised it actually allowes you to make http requests...)

A bug-free one (nonexistent). :)

In seriousness, the interview is supposed to give a taste of how the candidate thinks and codes in general. If they start using every obscure language feature under the sun, I am not too sure they got the idea.

Do you seriously believe, that someone who can write stuff like this can’t write ordinary code?
There are a lot of leetcoders who can't work in a team.

Maybe they work well on their own, or maybe their solutions collapse when given a problem of a complexity greater than the leetcode problems.

we just hardcoded the solutions for 1 to 100 manually. It's been fine so far.
The point of fizzbuzz is to figure out if you are not a rock. If you cant figure out how to code fizzbuzz from basic 8th grade logic something is wrong.
Enterprise FizzBuzz or go home!

Realistically this is an appropriate joke answer to a joke question.

I would probably post the idiomatic version in my programming language. Hopefully it will spark a discussion around language design. If not, perhaps it's a sign that the company is pretty rigid, and might not be a nice place to work.

    io:println¨ {⍵ (⊂"fizz") (⊂"buzz") (⊂"fizzbuzz") %⍨ 2 (⊥⍤1) ⍉ 0 = 5 3 |⌺ ⍵} ⍳20
Good effort but too straight-forward. Using an explicit, readable ternary operator is cheating in obfuscation.
If you do this on the interviewer's computer, their compiler can deal with undefined behaviour using physical violence. It's in the standard.
I get how this works, but this has undefined behaviour at multiple places.