07 April 1998
Here's the question again:
In what context will a routine containing this declaration
local
a: A
b: B
behave differently at runtime from the same routine with the order of declaration reversed:
local
b: B
a: A
The "gotcha" comes from the fact that a local entity may be expanded, in which case the creation routine (if any) will be automatically executed upon routine entry.
If we assume that local entities are initialized in order of declaration (an assumption that may be compiler-dependent), we can construct this system which executes to completion as shown, but fails ("feature call on void reference") if the order of declaration of 'a' and 'b' is reversed.
This is because when 'a' is declared first, the once-function is primed to always return the string "gotcha", so the call to 'to_upper' succeeds in both A and B. When 'b' is declared first, the once-function is primed to always return a void reference, so the call to 'to_upper' will fail in B (and would also fail in A if execution got that far).
class MAIN
creation make
feature
make is
local
a: A
b: B
do
end
end
expanded class A
inherit SHARED_ONCE_FUNCTION
creation make
feature
make is
do
once_function("gotcha").to_upper
end
end
expanded class B
inherit SHARED_ONCE_FUNCTION
creation make
feature
make is
do
once_function(void).to_upper -- fails if 'b' decleared before 'a'
end
end
class SHARED_ONCE_FUNCTION
feature
once_function(argument: STRING): STRING is
once
result := argument
end
end
Thanks to Alexei Kanatov of SIG Moscow for suggesting this one.
Eiffel and NICE are registered trademarks of the Nonprofit International Consortium for Eiffel.