Shop Learn
Boolean truth in Spin — Parallax Forums

Boolean truth in Spin

It took me a while before I hunted down this one:
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?



  • JonnyMacJonnyMac Posts: 7,412
    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.
  • ErlendErlend 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?

  • 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.
  • JonnyMacJonnyMac Posts: 7,412
    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.

  • 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
  • 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.

  • frank freedmanfrank freedman Posts: 1,791
    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....
  • 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.
  • ifnot (something false) comes in there handy...
Sign In or Register to comment.