-
-
Save caius/3027213 to your computer and use it in GitHub Desktop.
Argument mutation detection in Ruby (rough experiment)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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!