Share your repls and programming experiences

← Back to all posts
#WEEKLY 17 (Fibonacci Numbers)
fuzzyastrocat (1842)

For this challenge, I immediately turned to metaprogramming. (Sure, you could use the direct mathematical formula, but where's the fun in that? :D) I also decided to do the challenge in Ruby since I haven't had much experience with it. I ended up with 3 different programs, all of which perform the task:

My first attempt worked, but was very boring:

    puts "Enter the term number: "
    n,a,b = gets,0,1
    eval("a,b = b, a + b\n" * Integer(n))
    puts "Your answer is: " + String(a)

This is extremely straightforward, and definitely meets the requirements, but I decided to try something more fun as well. I managed to make a really, really weird iteration device which is guaranteed to work (though it is certainly not efficient):

    puts "Enter a term number:"
    n,$a,$b = gets,0,1

    class Abuse_Method_Missing
      def method_missing(methd, *args)
        $a,$b = $b,$a+$b

    cont =
    eval('def cont.' + eval("\"#{"a" * (Integer(n) + 1)}\"" + '.next' * Integer(n)) + "\n\tputs 'Your result is:'\nputs String($a)\nend")
    cont.send ("a" * (Integer(n) + 1))

What on Earth?

I told you it was weird :) Essentially, this is how it works:

  • We set up our constants, as per a standard iteration-based solution.
  • We define a container class so that our exploit, which involves method_missing, doesn't leak out into the global scope and cause weird stuff to happen.
  • We then define method_missing on this class — here we perform the basic fibonacci calculation. This is where the magic happens: we self.send a message which is equal to the "next" method after the method that called missing_method.
  • Then we make a new instance of our container class. After, we define the "ending-point" method on that class so that we don't trying to find the next method on that class. This is calculated by eval'ing the base method (which is defined as "a" * [term number] so that we don't wrap around, ie>aa) .next'd as many times as we want to do the calculation.
  • Finally, we send the "trigger" message, which is the base method as per the last step.

I was very happy when I got this working, but realized that the judges might consider this a form of recursion. So, consider my first solution as my "official" one.

Looking forward to how everyone decided to tackle this problem!

fuzzyastrocat (1842)

@TheDrone7 Oh, I'm new to this WEEKLY thing... how do I know what my score is?

AmazingMech2418 (1086)

Ah! I don't think the map function or spread operators are allowed...

fuzzyastrocat (1842)

@AmazingMech2418 Ah ok, my first solution is probably the most rules-abiding then. I actually just quickly made that solution because I realized that the second might be considered recursion, so I didn't stop to check if it really was good.

AmazingMech2418 (1086)

@fuzzyastrocat Well, metaprogramming to simulate recursion isn't recursion if that's what you mean.

fuzzyastrocat (1842)

@AmazingMech2418 True, I don't think it is. But some people (aka the judges) might consider self.send a form of recursion.

AmazingMech2418 (1086)

@fuzzyastrocat Generators are technically iteration/looping though...

fuzzyastrocat (1842)

@AmazingMech2418 Wait, Ruby's object model is based on generators?

mind blown

AmazingMech2418 (1086)

@fuzzyastrocat Well, if there is a next method, that is a generator.

fuzzyastrocat (1842)

@AmazingMech2418 Oh, you mean the Eh, I'd argue that's not a generator — it simply increments the string/name (aa -> ab, ab -> ac etc). I'm a Ruby newbie though (haha rhymes), but as I understand it just because it has a next method doesn't necessarily mean its a generator.

Jakman (449)

Does ruby have lazy iterators?

fuzzyastrocat (1842)

@Jakman I've never used them, but yes I believe it does.

fuzzyastrocat (1842)

@JosephSanthosh To me it's finicky, not hard. I mean, the fact that the whole idea of missing_method exists is really weird, but there's nothing particularly hard about that. I suppose the best way to describe it is that it takes some getting used to.

JosephSanthosh (1181)

Nice! Thanks a lot, do you think it's worth learning Ruby? @fuzzyastrocat

fuzzyastrocat (1842)

@JosephSanthosh My answer: No. I've never had an instance where I've had to use Ruby to do something, and since it hasn't increased my productivity I don't see why I'd ever chose to use it. I could be wrong, it just doesn't seem useful to me though. (Compare this to a functional language, Haskell, where I instantly noticed a productivity gain. I still like Haskell and chose to use it sometimes.)

JosephSanthosh (1181)

Oh ok! Thanks a lot! What is haskell i've never heard of it. @fuzzyastrocat

fuzzyastrocat (1842)

@JosephSanthosh Haskell is a functional programming language. This means that:
1. No variables! Variables literally don't exist, so a = 1; a = 2 is not possible.
2. Everything is done through the application of functions — there are no lists of statements. (You might think that Haskell's do is a list of statements, but it's actually just a clever abstraction.)
3. This means that code has no side effects — i.e, a function which is given the same arguments will always return the same thing.

Why on earth would you want these constraints? Well, if a program written in a functional programming language compiles, 9 times out of 10 it will do exactly what you want. If you want to know more (I probably explained it bad, FP is a really good thing believe me) check out the website:

JosephSanthosh (1181)

WOW! How can I ever thank you? You are so kind, thanks once again. @fuzzyastrocat