quinta-feira, 7 de agosto de 2008

Workaround for the Scoping Gotcha

My colleague pointed out to me today that you can get around the scoping issue I mentioned by writing your method like this :



Method f() {
set x = 6
set m = "write !,"_x ; difference
xecute m
}



What's the difference? Instead of including the name of the variable x inside the string, you concatenate the value of the local variable x with the string at run-time, before the string is finally evaluated. Because the value of x is resolved before the xecute, things work as you'd expect.

That's true. But I still regard this as a serious bug. An equivalent python program :



class A :
def f(self) :
x = 6
m = "print x"
exec m

x = 9
a = A()
a.f()



prints what you'd expect : the number 6.

What's really going on to cause this issue in Caché? My guess is that the OO layer in Caché is compiled down to plain Caché .int routines which don't have a significantly different semantics or scoping rules to Caché ObjectScript. In order to get the effect of the private world inside the object, at compile time the variable x is renamed to some object-specific equivalent. Of course, this renaming affects the real references to x, but not the string assigned to m.

When the VM then tries to xecute the string, it encounters the name x but finds no binding in the local execution frame and so, according to COS's dynamic scoping rules, has to look down the stack for a frame which does have a binding, the place from which we call y.f(), where x is bound to 9.

Of course, this hypothesis might be completely wrong. Expert correction is welcome.

2 comentários:

Frank disse...

That workaround wouldn't help on a real situation, because if you need to indirectly execute something is because you don't know what to be executed by the time you are going to execute. So, you can't do that switch on the workaround!

phil jones disse...

Frank.

I'm not convinced. :-)

I'd need to see a real example which a) genuinely depended on a string being passed as an argument to the method, b) the string referenced a local name in the method, and c) this was a *sane* way to solve a problem, rather than something constructed to trigger this bug.

I still agree that this is a bug and shouldn't be in Caché, but I accept that the work-around covers all the cases for which you might reasonably and safely be doing this kind of xecute.
Sending strings which contain names that are local to the method means that the outside is relying on information about the internals of the method that really should be hidden from it. That's just *so* wrong in every possible way.