Evaluation order in Spin
agodwin
Posts: 72
Does Spin have a fixed rule for evaluation order ? I have found the table of operator precedence, but sometimes it matters what order the expression is evaluated in.
e.g. in C,
if ((x = fn1(y) && fn2(x))
do_something();
else
do_something_else();
the language guarantees that fn1(y) will be evaluated before fn2(x) and that fn2(x) will not be evaluated at all if x turns out to be zero. This is quite handy as the equivalent nested statements result in two elses, not the single statement above.
When I did something similar in Spin, I had results which indicated that fn2 was being evaluated regardless of the result of fn1, and possibly with an uninitialized argument. This would not be surprising if Spin actually converts the expression to a stack representation and then evaluates it, which would be a fairly normal approach for a tokenised language.
So in retrospect, it's not that surprising that it didn't work (and since the argument was the address of a location to write in eeprom, ended up corrupting my program code ..) but if the behaviour is specified I'd like to read the rest of the rules.
-adrian
e.g. in C,
if ((x = fn1(y) && fn2(x))
do_something();
else
do_something_else();
the language guarantees that fn1(y) will be evaluated before fn2(x) and that fn2(x) will not be evaluated at all if x turns out to be zero. This is quite handy as the equivalent nested statements result in two elses, not the single statement above.
When I did something similar in Spin, I had results which indicated that fn2 was being evaluated regardless of the result of fn1, and possibly with an uninitialized argument. This would not be surprising if Spin actually converts the expression to a stack representation and then evaluates it, which would be a fairly normal approach for a tokenised language.
So in retrospect, it's not that surprising that it didn't work (and since the argument was the address of a location to write in eeprom, ended up corrupting my program code ..) but if the behaviour is specified I'd like to read the rest of the rules.
-adrian
Comments
I've never seen anything written down which guarantees fn1 gets executed before fn2 but the compiler follows what I'd consider normal code generation for a stack machine, left to right when precedence is equal.
Spin does have both bit logical operators (&, |) and Boolean operators (AND, OR) and the Boolean operators may use "short circuit" evaluation (I'm not positive). AND would correspond to && and OR would correspond to ||. In any event, the "short circuit" evaluation is a responsibility of the compiler, not the interpreter.
On programming language design side, I've never been comfortable with short-circuit evaluation. It seems to me that it should be all or nothing, if it is used in boolean evaluations it should be used everywhere; "x := y * fn(z)" should not evaluate fn(z) when y is zero.
When an evaluation is true or false based up whether zero or non-zero, how does one deal with bit-mask & and boolean AND in a consistent manner, in conditional execution and in assignments. It has always felt to me that short-circuiting is special case anomalous behaviour.
On top of that there's the complexity in mentally determining what exactly gets evaluated or not in some expression like "( a and b ) or ( c and d )" plus having to generate the code to do the short circuiting which I've never felt fits well with a stack machine architecture.
Admittedly, short-circuitry may rely on English semantics and therefore seem natural only to English speakers, for whom "or" often means "or else". I'm not sure the same is true in other languages (e.g. British ).
-Phil
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
'Still some PropSTICK Kit bare PCBs left!
For the following, with short-circuit evaluation the fn(z) would never be evaluated ...
a := true or fn(z)
b := false and fn(z)
@ Phil : I think perl's "or die" works so well because it's not really seen as short-circuit evaluation, more "or" as "or else", or as I read it "otherwise".
I cannot see any reason not to support "x ? y : z". Now you've suggested it I expect it will appear in all the third-party compilers quite shortly
Of course we already have "LookUpZ( (x<>0) & 1 : y, z )" but not so elegant.
I never use "x ? y : z" because I can never remember if true comes first or second, so expect the above <> to maybe be ==. In the languages I've designed I've always used -
var := if x then y else z
Post Edited (hippy) : 10/15/2008 2:33:19 AM GMT
a := LookUp( x ? -1 : -2 )
We can tell that's a 'lookup' on "reverse random of x less one" because it's the only valid construct but the compiler would not know that without a long look-ahead. Similar issues with 'case'.
Personally, I think it's stupid and a waste of time to continue evaluating a conditional when the outcome is already known...
But, I think you can achieve the same "short-circuit" results using nested conditionals.
I suppose one could add the && and || operators to Spin and let them short circuit. That way, current programs would not be broken. I rather like the Perl interpretation of these, BTW:
····this && that····If this is true (i.e. non-zero in Spin) return that else return this.
····this || that····If this is true return this else return that.
Also, while we're on the subject of Perlishness, unless as an idiom for if not would be a nice addition to Spin. I believe that the use of else with it should be preluded, though, due to the confusion it can cause.
Hippy, I'd forgotten about the random operator possibly interfering with x ? y : z. In point of fact, Spin already has such a construction ... sorta:
····lookupz((x <> 0) + 1 : y : z)
Its lack of terseness makes it a bit of a contrivance, though, and I'm not sure whether this construct gets short-circuited or not. (I suspect all the list items get evaluated before the selection is made.) I would much rather see an explicit construct that precluded the necessity for <> and +1. Perhaps
····ifelse(x : y, z)
is unambiguous enough to work.
-Phil
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
'Still some PropSTICK Kit bare PCBs left!
I re-visited my assertion that short-circit evaluation code generation is complicated for things like "( a and b ) or ( c and d )" on a stack-based machine and have to retract that claim. It's a lot easier than I thought it was ( perhaps that shows what I've learned in recent years ) but it does require two extra bytecode operators; jump if TOS is true and its false equivalent. That does require additional handling in an interpreter so it could well be a factor as to why Spin is as it is. That short-circuit evaluation increases code size could also be another reason for not selecting it.
Without short-circuit evaluation ...
With short-circuit evaluation ...
Post Edited (hippy) : 10/15/2008 6:29:40 PM GMT
-Phil
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
'Still some PropSTICK Kit bare PCBs left!
In your bytecode example, it looks like there could be some detritus left on the stack, depending upon which jumps were taken...
-Phil
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
'Still some PropSTICK Kit bare PCBs left!
if( a equals b and possibly c ) then if not why not
I've never seen IFNOT or ELSEIFNOT before, though I can see them being useful. It's certainly more legible than the C equivalent:
if( !(a == b) )
I find those !'s a little too easy to skim past.
Jason
A half decent compiler should be able to compile "IFNOT expr" and "IF not (expr)" to the same object code. The only thing it really achieves is in moving the scope of NOT without having to parenthesise the expression.
@ Rayman : I'll respect your view, but there are things which detract for me; having to wrap conditionals in parenthesis when there is no need and, without going non-standard, not being able to manipulate bits in variables and registers directly other than by masking, the lack of bit or intrinsic boolean variables, the platform specific size of some variable types. I personally loath the "for" construct in C.