Evaluation order in Spin

agodwinagodwin Posts: 72
edited 2008-10-16 - 12:52:43 in Propeller 1
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

Comments

  • mparkmpark Posts: 1,175
    edited 2008-10-14 - 22:19:41
    I don't know if the rules are written down anywhere, but yes, Spin evaluates everything. No short-circuiting, no optimizations.
  • hippyhippy Posts: 1,981
    edited 2008-10-14 - 23:01:02
    Operator precedence is in Table 4-10 on page 251 of the Propeller Manual. The only 'special case' I found I had to watch out for is NOT which has a different precedence to some other languages. As noted, no short-circuiting.

    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.
  • RaymanRayman Posts: 9,716
    edited 2008-10-14 - 23:51:26
    I think it would have been better if this were handled like C so that the second evaluation would be skipped if the first were false. But, maybe Chip was down to his last byte of ROM and and to skip things...
    Prop Info and Apps: http://www.rayslogic.com/
  • Mike GreenMike Green Posts: 22,917
    edited 2008-10-15 - 01:07:32
    Rayman,
    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.
  • hippyhippy Posts: 1,981
    edited 2008-10-15 - 01:45:46
    I personally prefer not having short-circuit evaluation, mainly because that's what I'm most used to, it's C which catches me out. I expect those more familiar with C will feel differently. "What would have been better for Spin" will come down to individual preferences and preferred experiences.

    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.
  • Lord SteveLord Steve Posts: 206
    edited 2008-10-15 - 02:05:10
    Short circuiting is kind of like a lazy else clause, no?
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 22,443
    edited 2008-10-15 - 02:18:25
    As a Perl programmer, I delight in short-circuit evaluation (e.g. live(free) or die;) and use it wherever I can. To me, the terseness it affords makes programs both elegant and readable. I wish Spin were designed to accommodate it, along with the very useful trinary x ? y : z construct. (It's too late for the former, but not for the latter.) Short-circuit evaluation does complicate code generation, though, especially in complex expressions like Hippy's example.

    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 smile.gif ).

    -Phil

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    'Still some PropSTICK Kit bare PCBs left!
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • hippyhippy Posts: 1,981
    edited 2008-10-15 - 02:18:39
    @ Lord Steve : That's one way of describing it. If a boolean expression can be determined by the first part the second part does not need to be evaluated.

    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 smile.gif

    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
  • hippyhippy Posts: 1,981
    edited 2008-10-15 - 10:36:51
    Thinking about adding "x ? y : z" I don't think that's possible because of the ambiguity between "?" and its use as a post-unary operator ...

    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'.
  • RaymanRayman Posts: 9,716
    edited 2008-10-15 - 12:07:14
    Mike: I asked before and was told that Spin does not use "short-circuit" evaluation.

    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.
    Prop Info and Apps: http://www.rayslogic.com/
  • Mike GreenMike Green Posts: 22,917
    edited 2008-10-15 - 14:35:17
    This discussion (about "short-circuit" evaluation) was had back in the days when C was new and Pascal was introduced. There are important theoretical considerations for not using it or providing both forms or making it optional. Again, this has to do with possible "side effects" of the function calls where what happens when the function is called is more important to the program than the result returned. It's certainly not stupid, may sometimes be inefficient, but not a waste of time to completely evaluate the expression as written. Like a lot of things involving tools, if it's not something you're used to, it may look dumb or stupid, but usually it's well thought out and reasoned, just different. You may disagree with the reasons behind it, but that doesn't make them wrong and it doesn't make your reasoning wrong either. The circumstances behind the reasons may be different.
  • RaymanRayman Posts: 9,716
    edited 2008-10-15 - 15:42:55
    I did say "Personally"...
    Prop Info and Apps: http://www.rayslogic.com/
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 22,443
    edited 2008-10-15 - 15:59:04
    One thing that's helped by not short-circuiting is determinism. All else being equal, the byte codes corresponding to a logic expression should always execute in the same amount of time if they're not aborted by a short circuit. Of course, by including function calls in such an expression, all bets are off. There may also be native operations whose execution time is operand-dependent.

    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!
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • hippyhippy Posts: 1,981
    edited 2008-10-15 - 16:15:30
    There's also the issue of ease of implementation; the simplest has to be 'sod it, just evaluate everything'.

    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 ...
        PSH  a
        PSH  b
        AND
        PSH  c
        PSH  d
        AND
        OR
    
    


    With short-circuit evaluation ...
        PSH  a
        JIF  L1
        PSH  b
        AND
    L1: JIT  L3
        PSH  c
        JIF  L2
        PSH  d
        AND
    L2: OR
    L3:
    
    

    Post Edited (hippy) : 10/15/2008 6:29:40 PM GMT
  • hippyhippy Posts: 1,981
    edited 2008-10-15 - 16:19:21
    @ Phil : There is "IFNOT" and "ELSEIFNOT" in Spin.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 22,443
    edited 2008-10-15 - 16:53:13
    Oh, you're right. I still like UNLESS and ELSEUNLESS better. UNLESS parallels UNTIL (as opposed to WHILENOT) a little better.

    -Phil

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    'Still some PropSTICK Kit bare PCBs left!
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 22,443
    edited 2008-10-15 - 17:00:35
    Hippy,

    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!
    “Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -Antoine de Saint-Exupery
  • hippyhippy Posts: 1,981
    edited 2008-10-15 - 18:29:05
    Well spotted, post updated. I recommend people use computers for compilation, not doing it by hand smile.gif
  • JasonDorieJasonDorie Posts: 1,930
    edited 2008-10-15 - 23:34:57
    With all those 'english-like' operators you're getting painfully close to a geek joke from years ago:

    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
  • RaymanRayman Posts: 9,716
    edited 2008-10-16 - 02:31:17
    C is pure beauty in my eyes...
    Prop Info and Apps: http://www.rayslogic.com/
  • hippyhippy Posts: 1,981
    edited 2008-10-16 - 12:52:43
    Re, IFNOT : I'm not sure why it's needed ( and I haven't looked at the code generated ) but I guess it's the same reason as to why I've implemented it at times; it saves having to optimise generated code, moves optimisation into the hands of the programmer and away from the compiler.

    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.
Sign In or Register to comment.