Re: init.e - standard library candidate
- Posted by jimcbrown (admin) Mar 16, 2013
- 1453 views
I suspect this is simply broken.
Based on what you demonstrate below, I can understand why you would think that. After making the following analysis, I find that I concur with your suspicion, but possibly for different reasons.
What should the following do?
somefile.e
constant A="1" global procedure putsomething(sequence s=A) puts(1,s) end procedure
someotherfile.exw
include somefile.e constant A="2" putsomething() if getc(0) then end if
It should print 1, as the resolution of variable names for defaulted parameters - when the default is used - should be done in the context of the file where the routine is declared, not in the context of where it is used.
I'm quite happy that it prints 1, but that is not what was said, and routine_id is breaking scope by working...
Pete
Debatable.
Here's a modified version:
somefile.e
constant A="1" function it(sequence s) return s*1 end function global procedure putsomething(sequence s=A, sequence b=it(s), sequence c=repeat(s,10)) puts(1,s) puts(1,b) ? c end procedure
otherfile.exu
include somefile.e constant A="2" putsomething() putsomething(A)
It first prints out "11" followed by a sequence containing sequences of 49 (or "1"), but the second time around it prints out "22" etc. When a preceding defaulted parameter is overridden, and succeeding defaulted parameters which use it are not, then they should use the new caller-passed overridden value in preference to the original, defaulted value.
Thus, like repeat() and it() in the example above, a defaulted parameter that uses routine_id(s) in the same way should expect that when s is overriden, then the following parameter(s) that use routine_id(s) will use the new overidden value for s as well.
However, routine_id() is unique in that, like repeat() or it(), routine_id() relies on scoping to interpret the value of its parameter. So, what should routine_id() do? Should it use the scope where the routine is called, or the scope where the routine is defined? This only applies to routine_id(), since no other routine cares about scope in the same way when it is called.
I contend that the most natural way for this to work is that routine_id() should use the scope where the routine with the defaulted parameter is defined when no relevant variables are overidden by the caller (as the defaulted routine_id() call probably points to a local routine that may not be visible in the caller's scope), but when overriding occurs then it should use the caller's scope (as the caller probably wants to take the routine id of a local routine that was immediately defined - e.g. setHandler() and routine_id() are typically called together immediately after the declaration of the handler routine).
Based on that, I would conclude that this is indeed broken, because routine_id() always defaults to the callers scope.
Example:
somefile.e
constant A="1" constant AA="it" function it(sequence s) return s*1 end function global procedure putsomething(sequence s=A, sequence b=it(s), sequence c=repeat(s,10), sequence d=AA, integer e=routine_id(d)) puts(1,s) puts(1,b) ? c ? e end procedure
otherfile.exu
include somefile.e constant A="2" procedure AA() end procedure putsomething(A)
This prints out -1 at the end, when it should print out a valid routine_id() for the routine "it".
That said, I suspect that fixing routine_id() to work intelligently in what I contend is the most natural manner is probably very difficult, while working around this behavior is really easy.
If the current behavior is kept as is, then the caller can simply manually invoke routine_id() if the integer holding the routine id is -1 and the sequence holding the routine name is the same as the default.
Example:
constant A="1" constant AA="it" function it(sequence s) return s*1 end function global procedure putsomething(sequence s=A, sequence b=it(s), sequence c=repeat(s,10), sequence d=AA, integer e=routine_id(d)) puts(1,s) puts(1,b) ? c if equal(d, AA) and e = -1 then e = routine_id(AA) end if ? e end procedure
otherfile.exu
include somefile.e constant A="2" procedure AA() end procedure putsomething(A)
However, altering routine_id() so it always uses the scope of the callee is not useful, as the callee has no way to compenstate and discover the real routine id that is meant to be called from just the string. Instead, the integer with the routine_id() call must be overriden everytime - most likely by another handwritten routine_id() call directly in the caller (as is typically done with setHandler() ). This makes embedding a routine_id() call inside of a defaulted parameter unconditionally useless.
So, yes, maybe it is technically broken, but if it can't be fixed, then breaking it in this way is better than the alternative.