Boolean truth in Spin — Parallax Forums

# Boolean truth in Spin

Posts: 612
It took me a while before I hunted down this one:
Apparently
```IF  CupWas== FALSE  AND CupIs== TRUE
```
compiles but does not work, whereas
```IF  NOT CupWas  AND CupIs
```
works as intended.
I am not sure why?

Erlend

• Posts: 7,554
edited 2020-01-01 01:27
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.
• Posts: 612
edited 2020-01-01 09:25
Remains strange. I only used TRUE and FALSE as values, e.g.
```CupWas:= TRUE
CupWas:= FALSE
```
so I should not have to worry about the underlying values of those two constants?

Erlend
• Posts: 7,554
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.

• Posts: 3,438
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.
• Posts: 7,554
edited 2020-01-01 20:20
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.

• Posts: 1,612
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
```if someVariable == false
```
is slower and bigger than
```if not someVariable
```
which is in turn slower and bigger than
```ifnot someVariable
```
• Posts: 612
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.

Erlend
• Posts: 1,828
edited 2020-01-03 06:44
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....
• Posts: 3,438
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.
• Posts: 3,341
ifnot (something false) comes in there handy...