Skip to content

Instantly share code, notes, and snippets.

@caius
Forked from peterc/mutation_detection.rb
Created July 1, 2012 06:42
Show Gist options
  • Save caius/3027213 to your computer and use it in GitHub Desktop.
Save caius/3027213 to your computer and use it in GitHub Desktop.
Argument mutation detection in Ruby (rough experiment)
# encoding: utf-8
# This is a very early scrappy step in building an automatic memoizer (think IncPy)
# in pure Ruby. Is it possible? Who knows. A first step, then, is to rule out any
# methods that mutate their parameters.. which I attempt to do here.
module AutoMemoize
CaughtMutation = Class.new(StandardError)
def monitor meffod
unbound_meffod = instance_method(meffod)
define_method(meffod) do |*args, &blk|
oldargs = Marshal.load(Marshal.dump(args))
unbound_meffod.bind(self).call(*args, &blk).tap do
btrace = (unbound_meffod.source_location + ["in `#{meffod}'"]).join(':')
raise AutoMemoize::CaughtMutation, nil, btrace if oldargs != args && !blk
end
end
end
def method_added(meth_name)
return false if self == Class || meth_name[-1] == "="
@meths ||= {}
unless @meths[meth_name]
@meths[meth_name] = true
monitor meth_name
end
end
end
Class.send :include, AutoMemoize
# --- the above would all be in a library/separate file that you required in first
# --- the below is 'normal' application code
class Adder
def add(a, b)
a.push("oh dear") # comment this out to 'fix' the problem
a + b
end
end
a = Adder.new
p a.add(%w{a b c}, %w{d e f})
@peterc
Copy link

peterc commented Jul 1, 2012

Good call. Now I'm intrigued why the New Relic RPM agent doesn't do this since that's where I got some of the inspiration for this idea. They pass strings of code around and eval them. Finding a nicer/more efficient way to do the mutation checking would be nice too. I believe using #hash would work well for this. Will keep these ideas in mind - thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment