Keep in mind that true is equal to -1 so your first style is restrictive, i.e., cupIs must be -1 for the entire expression to evaluate as true. The second variation works because in that style (without equality testing), any non-zero value is considered true. False = 0, hence not false (not zero) evaluates as true.
so I should not have to worry about the underlying values of those two constants?
You're right, but in the heat of battling your code you may have stepped over something -- these issues can be very subtle.
It doesn't appear to be an operator precedence issue. Still, I am a big fan of parenthesis to make sure the compiler is evaluating things the way I want. I would code your first line like this
if ((cupWas == false) and (cupIs == true))
' do something
Likewise, I would code the second variant like this:
if (not(cupWas) and cupIs)
' do something
It's just a few extra keystrokes and removes any ambiguity. I think this is helpful because you're treating everything as a logical operator; this gives you a bit of flexibility with what is considered true (false is always 0).
It looks like you're doing a test of a transition from off to on. Here's a trick I use with a simple state variable.
state := (state << 1) & %11
if (on_condition)
state |= 1
case state
%00 : { off }
%01 : { new on transition }
%11 : { on }
%10 : { new off transition }
If you're using this to monitor an input pin you can modify the first line and get rid of the if() section.
state := ((state << 1) & %11) | ina[pin]
Again, using parenthesis makes the code absolutely clear -- to me, and to the compiler.
In addition to the precedence issue JohnnyMac mentions, Spin is unlike most languages in having two forms of boolean operators. Spin is like most languages in not having a true boolean data type; it uses integers for that, with the convention that 0==false and anything else==true. Most languages do bitwise logical operations and this can cause problems. For example, if you have variables containing 8 or %1000 and three or %0011, if you logical-and them together even though both are nonzero/true you will get zero/false because they don't share any bits. Spin solves this by providing the "spelled" operators AND, OR, NOT which normalize everything to -1 before doing the logical operation and always return -1. When you need bitwise logic you use &, |, and so on. Most languages don't make this distinction.
In Spin you also have the problem of non-Long variables. If you define A as a byte, and test (if A == TRUE) it will never be true because A is a byte and if it is "true" aka all-bits-on it will evaluate to 255, while TRUE is 32-bit -1. Spin provides the sign extension operators but these are very arcane and not found anywhere else, and it's safer just to understand that non-Long variables are never true unless evaluated via spelled logic operators.
All this can be very confusing if you're new to it and even more so if you're coming from a particular environment like BASIC where the spelled operators are bitwise, Javascript where all numeric data are the same, or Lua which actually has a boolean data type. Unfortunately the only sure cure for it is to understand that boolean data are numbers in Spin, and to know how and when they are zero and -1 and what pitfalls arise when other values are evaluated.
In Spin you also have the problem of non-Long variables.
Thank you, Roger, I didn't even think about that -- would explain why Erland's first scenario fails and the second works.
@Erland: If cupWas and cupIs are bytes, assigning either to true results in the value 255 (max value for 8 bits), which is not equal to the long value of true (-1) used by the language. In this case your code evaluates as:
if 0 == 0 and 255 == -1
This illustrates how tricky using true and false with == can be. Since the value of false is always 0 and fits into any variable, you could do this:
if cupWas == false and cupIs <> false
This will work, but seems inelegant. I think code should always be elegant.
An additional element of consideration: The Spin compiler is really "dumb". (Well, Propeller Tool/Homespun/openspin)
It will translate exactly what you wrote into bytecode.
Such it is that
Nice. A bunch of learning for me. I am not new to Spin, or BASIC, or Lua, or Delphi - but I keep needing to learn all the same. I had the variables defined as BYTE.
Thanks also for the state-monitoring code.
Well this was a timely thread! Had a similar situation but have not had time to ask the question. Never had this happen before due to jumping straight to PASM, now going back to spin for a project. Many thanks y'all....
Well I've been bitten by the nozero <> TRUE thing before myself. It may not seem elegant but I find that even with the spelled logical operators the safest thing is to never assume anything == TRUE and always test against FALSE even if that involves inversion. FALSE is false at all data widths and you can trust it.
Comments
Erlend
It doesn't appear to be an operator precedence issue. Still, I am a big fan of parenthesis to make sure the compiler is evaluating things the way I want. I would code your first line like this Likewise, I would code the second variant like this: It's just a few extra keystrokes and removes any ambiguity. I think this is helpful because you're treating everything as a logical operator; this gives you a bit of flexibility with what is considered true (false is always 0).
It looks like you're doing a test of a transition from off to on. Here's a trick I use with a simple state variable. If you're using this to monitor an input pin you can modify the first line and get rid of the if() section. Again, using parenthesis makes the code absolutely clear -- to me, and to the compiler.
In Spin you also have the problem of non-Long variables. If you define A as a byte, and test (if A == TRUE) it will never be true because A is a byte and if it is "true" aka all-bits-on it will evaluate to 255, while TRUE is 32-bit -1. Spin provides the sign extension operators but these are very arcane and not found anywhere else, and it's safer just to understand that non-Long variables are never true unless evaluated via spelled logic operators.
All this can be very confusing if you're new to it and even more so if you're coming from a particular environment like BASIC where the spelled operators are bitwise, Javascript where all numeric data are the same, or Lua which actually has a boolean data type. Unfortunately the only sure cure for it is to understand that boolean data are numbers in Spin, and to know how and when they are zero and -1 and what pitfalls arise when other values are evaluated.
@Erland: If cupWas and cupIs are bytes, assigning either to true results in the value 255 (max value for 8 bits), which is not equal to the long value of true (-1) used by the language. In this case your code evaluates as: This illustrates how tricky using true and false with == can be. Since the value of false is always 0 and fits into any variable, you could do this: This will work, but seems inelegant. I think code should always be elegant.
It will translate exactly what you wrote into bytecode.
Such it is that is slower and bigger than which is in turn slower and bigger than
Thanks also for the state-monitoring code.
Erlend