Sorry to get real-worldy on an academic discussion, but there’s a much
easier ruby solution:
Make it so that a Proc can be a valid lvalue:
class Proc; def =(*a) self[*a] end end
def trace_array( an_array, msg )
proc { |*args|
if args.length() == 1 then
p “#{msg}: Read access at pos #{args[0]}”
an_array[args[0]]
elsif args.length() == 2 then
p “#{msg}: Write access at pos #{args[0}”
an_array[args[0]] = args[1]
else
p “#{msg}: Weird access.”
an_array[*args[0…-1]] = args[-1]
end
}
enddef buggy_meth()
a = [1,2,3]
a = trace_array( a, “a in buggy_meth()”) if $Debug
… use a …
endIn this example you can substitute a Proc where an Array was expected.
The Proc is invoked both for read and write accesses to the Array.
It outputs a msg and then performs the required operation on the
Array.This is a simple debugging tool made possible thanks to an additional
level of indirection.
irb(main):001:0> a = [1,2,3]
=> [1, 2, 3]
irb(main):002:0> class << a
irb(main):003:1> def =(idx, val, *args)
irb(main):004:2> puts “accessed as #{idx.to_s}, #{val.to_s},
#{args.to_s}”
irb(main):005:2> super(idx,val)
irb(main):006:2> end
irb(main):007:1> end
=> nil
irb(main):010:0> a[0] = 2
accessed as 0, 2,
=> 2
irb(main):011:0> a
=> [2, 2, 3]
irb(main):012:0>
You can always achieve indirection by redefinition. It’s easier on the
brain.
Proc (and method) do not to me make sense as p[1] = x (or m[1] = x).
They can only make sense when there’s a reciever, i.e. obj.m[1] = x.
This then, is simply method chaining: obj.get_m.=(1,x). Proc is an
anonymous method bound to some reciever, but obeys the same rules.