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

I agree that Fizzbuzz can be a more interesting example of how to write code without repetition. While the author suggests that languages such as Haskell provide a unique advantage, the deciding question seems to be the availability of pre-built abstractions. Consider the following solution in Python:

  for i in xrange(1,101): print (('' if i%3 else 'Fizz')+('' if i%5 else 'Buzz')) or i
or the even more general:

  mapping={3:'Fizz',5:'Buzz'}
  for i in xrange(1,101): 
    print ''.join(['' if i%x else mapping[x] for x in mapping]) or i
We can even do this in C though to write something as extensible as the second would require writing more helper functions than I can justify for this brief comment:

  #include<string.h>
  #include<stdio.h>
  int main(){
    int i;
    char s[4];
    char n[3];
    for (i=1;i<101;i++){
      sprintf(n,"%d",i)
      s=strcat((i%3)?"":"Fuzz",(i%5)?"":"Buzz")
      printf("%s",(strlen(s))?s:n)
    }
    return 0;
  }


My "I'm going to hell, but that's okay" C version:

  #include <stdio.h>
  #include <stdbool.h>

  #define when(mod, msg) do { if((i mod) == 0) { fputs(#msg, stdout); *hit = true; } } while(0)
  #define through ; i <=
  #define engine(range) \
  void rules(int, bool *);\
  int main(void) { for(int i = range; ++i) { bool hit = false; rules(i, &hit); if(!hit) printf("%d", i); putchar('\n'); } } \
  void rules(int i, bool *hit)

  engine(1 through 100) {
    when(% 3, Fizz);
    when(% 5, Buzz);
  }
Super extensible!


I'm not sure even hell will take you after doing what you just did. There is no metaphysical consequence great enough save to have experienced the writing of that.


My "I'm going to hell" C++ version: https://gist.github.com/3838042

Or, since github's being broken right now:

    #include <iostream>
    #include <arpa/inet.h>
    
    template <int multiples_of, uint32_t noise>
    class Noisemaker {
    private:
        union {
            uint32_t noise_as_int;
            char noise_as_cstr[5];
        };
    public:
        Noisemaker() {
            noise_as_int = htonl(noise);
            noise_as_cstr[4] = '\0';
        }
        bool operator()(std::ostream &out, int i) {
            if(i % multiples_of == 0) {
                out << noise_as_cstr;
                return true;
            }
            return false;
        }
    };
    
    template <typename Noise1, typename Noise2>
    class NoisemakerPair {
    private:
        Noise1 noise1;
        Noise2 noise2;
    public:
        bool operator()(std::ostream &out, int i) {
            bool matched = false;
            matched |= noise1(out, i);
            matched |= noise2(out, i);
            return matched;
        }
    };
    
    int main(int argc, char *argv[]) {
        NoisemakerPair<Noisemaker<3, 'Fizz'>, Noisemaker<5, 'Buzz'> > fizzbuzz;
        for(int i=1;i<=100;++i) {
            if(!fizzbuzz(std::cout, i))
                std::cout << i;
            std::cout << std::endl;
        }
    }
You can nest NoisemakerPairs to add more Noisemakers. But good luck with strings longer than 4 characters… for some absurd reason, string literals can't be template parameters. Go figure.


My going to hell version:

https://github.com/rcs/fizzbuzz/blob/master/bitwise.c

Choice excerpts:

  char fmts[] = "FizzBuzz%u";
and

      // Default start is 8
    unsigned int start =
      // Shift down 1 if div5
      (8 >> DIV5(mask))
      // Shift down another 4 if div3 */
      >> ( DIV3(mask) << 2);


It is still crazy to me that in Python

    ('' or 10) == 10 # True
That's like making the universe crazier one electron at a time.

But yes, it's just about having the right abstractions. What's nice about the Haskell solution is that the right abstractions make the code much nicer (to my eye).


I honestly don't understand why that's crazy. Empty string evaluates as falsey, so the "or" picks the 10, which is obviously equal to 10. Or am I missing something?


It just seems like a bad choice. The empty string being falsey is... very arbitrary to me. It seems like it's strictly a perl legacy thing that should be (but cannot be) reconsidered.

About as far as I am willing to go is nil punning.


FWIW - it has been reconsidered in Ruby - all values are truthy except nil and false.


> The empty string being falsey is... very arbitrary to me.

It's extremely useful in a lot of contexts. The basic logic is that an empty string is an empty container, and empty containers are false, so you can test for them more easily.


Breaks the spec: 'Write a program that prints the numbers from 1 to 100. But for multiples of three print “Fizz” instead of the number and for the multiples of five print “Buzz”. For numbers which are multiples of both three and five print “FizzBuzz”.'

Actually, this spec is ambiguous, too. For multiples of five, do we print the number AND "Buzz" or just "Buzz" ? Similarly for multiples of 15.

I thought the OP was a joke, BTW. It had to be, doesn't it? If somebody thought of this problem and solution the way the job candidate did, why on earth would one want to hire somebody who loves complexity for its own sake?

To me, the following is the clearest way to express this (in C anyway). I suppose it says a lot about me! lol

#include <stdio.h> #define FALSE (0) #define TRUE (!FALSE)

int main(){

  for(int i=1; i <= 100; i++){
    int printed_something_already=FALSE;
    if(i%3 == 0){
      printf("Fizz");      printed_something_already=TRUE;
    }
    if(i%5 == 0){
      printf("Buzz");      printed_something_already=TRUE;
    }
    if(!printed_something_already) printf("%d",i);
    printf("\n");
  }
  return 0;
}


> I thought the OP was a joke, BTW.

Well balls to you too, I guess? Or not. We're all just trying to have a good time here. And from the look of this thread, people are having fun.

I think golfing fizzbuzz into an unreadable mess sorta misses the point, but most people here are software engineers because they love to code and build stuff. So let's enjoy the moment.

> why on earth would one want to hire somebody who loves complexity for its own sake?

You remind me of: http://wondermark.com/333/

It's not complexity for its own stake. I daresay the functional patterns tend to be simpler. Certainly moreso than things like Visitor or AbstractFactory.

> To me, the following is the clearest way to express this (in C anyway). I suppose it says a lot about me!

Your version is almost identical to the Ruby version I listed. And it's an appropriate solution for C.


I don't know what balls to me too means.

Yes, if we're all trying to have a good time, we'd shoot heroin and be done with it. ;-) IMHO, we are group sharing to learn better ways to build startups, small businesses, and to better ourselves, co-workers, and companies with best practices - and to do it with fun and a twinkle in our eyes.

I did look at that wordmark comic -- I believe I ask a credible question: If complexity buys you nothing, then why make something complex? And, believe me, if you are thinking "Visitor" or "AbstractFactory" then I have already lost you. ;-)

Thank you for your comment about my C version. I wanted to make sure it was extensible and quite obvious -- because I write code to be read by humans as my 2nd goal (my first is that it works & meets the spec!). Knuth's Literate Programming taught me that. The other thing about that C solution is that it's simple and many people can understand it. One does not need to know the difference between a monad and a gonad to "get it".

My overall comment: Complexity: when required; otherwise, choose simple. Believe me, I have learned this lesson over and over again during my 45 years of programming.


> If complexity buys you nothing, then why make something complex? And, believe me, if you are thinking "Visitor" or "AbstractFactory" then I have already lost you. ;-)

I think maybe the disconnect here is that I work on products with a much larger scale than you may be accustomed to. My idea of complexity begins to blossom at scales past many boxes. For me, 25 interconnected machines is barely enough to register as a "big system". So perhaps I am just desensitized?

Abstraction is generally trying to find ways to mitigate complexity, not embrace it. At some point we need to have sympathy for the machines we run on to have efficient code, but at the same time you and I need to find good perspectives to write code at.

A more concrete example of this is my advice that people building distributed systems take a cue from Boundary and have systems rendezvous in Zookeeper rather than just using something like hardwired ports and /etc/hosts. You may think that "sounds complex" but it's actually a very simple solutin from our perspective as users of Zookeeper. It ends up being pretty nice the next time a giant storm takes out half of us-east-1 and you're frantically re-provisioning boxes to keep your service up.

Monoids are that kind of choice at the programming level.

> Complexity: when required; otherwise, choose simple. Believe me, I have learned this lesson over and over again during my 45 years of programming.

I think c_wraith's monoid example made the program simpler, cleaner, and less bug prone. If you think monoids are a "complex" idea, then my blog post has failed profoundly and I apologize for wasting your time.


I believe that efforts using trivial examples to show how complexity can be managed via certain abstractions are doomed to fail.

And that's a pity, because it makes abstractions harder to explain in a proper context.

You need an example where the complexity at least rears its ugly head before the abstraction starts to shine.

For many people, especially those not familiar with it at the time of the reading, the simple example using a manage huge complexity abstraction reeks of "complexity for its own sake" or "killing flies with a cannon" or "premature optimization" and it's natural because the example is not showing the strengths of the abstraction, rather its weaknesses.


> I believe that efforts using trivial examples to show how complexity can be managed via certain abstractions are doomed to fail.

I've received 5 emails and about 10 tweets from people saying, "I think I understand monoids better because your tutorial sat at the right level of abstraction and overhead for me to get."

So, I think I succeeded for 15 people. Which I am pretty damn happy about. Because whenever I write one of these I pretty much assume everyone will misread, misunderstand, or ignore 3/4 of my post. It's just my experience.

People who call the monoid abstraction "confusing" and "complexity for its own sake"... I just have to assume these people can't handle the discomfort of learning new concepts anymore and write them off as unreachable. It's not like I owe them anything. Because I'm pretty sure it's actually not confusing at all, it's just a different perspective.

The real irony is that for awhile I was deep in the OO and Ruby culture and said a lot of these same things. You can find them online if you know where to look. So I understand where these people are coming from and know that without their cooperation, I cannot explain anything at all.


FWIW, you can count me in. I've understood monoids better thanks to your article.

My comment was not a jab at your article, but a comment on how hard it is to find the proper abstraction level.

And that I fully understand people who'd say it is making things more complex for its own sake, and I'm not sure it necessarily is because they don't want to learn.


Just as you can write FORTRAN or COBOL in any language, you can write functional code in any language.


No you can't, as you need the language to provide a few basic building blocks, such as lambdas, and the ability to pass functions as arguments.


You can generally approximate higher order functions in almost every OOP language. See C++ before it got lambdas, they have a pattern. See also java's anonymous inner classes, which are often used with the Runnable interface for that rule.


In the Python example, wouldn't you need to make sure the x values from mapping are sorted, since dictionaries are unordered? Change, for x in mapping to for x in sorted(mapping)




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

Search: