Fun With Ruby Metaprogramming


def foo
  'bar'
end
#=> :foo
  

Memoization


def fibonacci(n)
  return 1 if n <= 1
  fib(n-1) + fib(n-2)
end
  

def fib(n)
  # ...
end
#=> :fib
  

def fib(n)
  # ...
end

memoize :fib
  

memoize def fib(n)
  # ...
end
  

class Calculator
  extend Memoization

  memoize def fib(n)
    # ...
  end
end
  

calc = Calculator.new
calc.fib(1000)
  

module Memoization
  def memoize(name)
    #
  end
end
  

def memoize(name)
  @@cache ||= {}
  @@cache[name] = {}
  # ...
end
  

def memoize(name)
  @@cache ||= {}
  @@cache[name] = {}

  fn = instance_method(name)
  # ...
end
  

def memoize(name)
  # ...
  instance_eval do
    define_method(name) do |*args|
      # ...
    end
  end
end
  

define_method(name) do |*args|
  if @@cache[name].include?(args)
    # return from @@cache
  else
    # calculate and update @@cache
  end
end
  

if @@cache[name].include?(args)
  @@cache[name][args]
else
  @@cache[name][args] = fn.bind(self).call(args)
end
  

class Calculator
  extend Memoization

  memoize def fib(n)
    # ...
  end
end
  

Class methods


static def fib(n)
  # ...
end

Calculator.fib(100)
  

def static(name)
  fn = instance_method(name)
  define_singleton_method(name) do |*args|
    fn.bind(self.new).call(args)
  end
end
  

memoized static def fib(n)
  # ...
end

Calculator.fib(100)
  

Tail call optimization


def factorial(n)
  n <= 1 ? n : n * factorial(n-1)
end
  

def factorial(n, acc=1)
  return acc if n <= 1
  factorial(n-1, acc*n)
end
  

class Calculator
  extend TailCallOptimization

  tail_recursive def factorial(n, acc=1)
    # ...
  end
end
  

module TailCallOptimization
  RubyVM::InstructionSequence.compile_option = {
    tailcall_optimization: true,
    trace_instruction: false
  }
end
  

module TailCallOptimization
  def tail_recursive(name)
    fn = instance_method(name)
    undef_method name
    # recompile method with TCO
  end
end
  

def tail_recursive(name)
  # ...
  RubyVM::InstructionSequence.new(<<-EOS).eval
    class #{to_s}
      #{fn.source}
    end
  EOS
end
  

Other ideas


# Raises error if result is not a Fixnum
typecheck Fixnum, def foo
  # ...
end
  

# Please don't
public static void def main()
  # ...
end