Are digital pin states acting as boolean values indended or a misfeature?

I'd like to apologize if this question has been answered already, but all my search attempts return way too many unrelated results.

I've experimented and found that the result of a DigitalRead (result HIGH or LOW) acts as the boolean values TRUE and FALSE. For example:
variable = DigitalRead(4); if (variable == HIGH) and if (DigitalRead(4) == HIGH) and if (DigitalRead(4)) function identically. Honestly, I forget if I did this experiment in 1.0.3 or 1.5.2b. I don't think I've used 1.0.4 yet, but I could be mistaken... I do know I tested this on an UNOr3.

Is this intentional behavior that can be relied on continuing in future versions of the ArduinoIDE, or is this a misfeature that may be corrected at some point breaking code written to exploit this behavior?

Also, for code optimization, what creates the smallest binary and/or uses the least clock cycles? Comparing the result of DigitalRead() to a constant to get a boolean result or just taking the result of DigitalRead() directly as a boolean value?

In C, any non-zero value is taken as 'true' in a boolean context, so it is perfectly leagal behaviour. Only all bits zero is taken as 'false'.

I've experimented and found that the result of a DigitalRead (result HIGH or LOW) acts as the boolean values TRUE and FALSE. For example:

HIGH is a constant, valued 1. LOW is a constant, valued 0.

TRUE is a constant, valued 1. FALSE is a constant, valued 0.

In C, false is 0, and true is anything but 0.

Is this intentional behavior that can be relied on continuing in future versions of the ArduinoIDE, or is this a misfeature that may be corrected at some point breaking code written to exploit this behavior?

It is reasonably certain that nothing will change. One should NOT rely on that, though. It is not that difficult to type:

if(digitalRead(somePin) == HIGH)

making the meaning EXPLICITLY clear, compared to

if(digitalRead(somePin))

Sembazuru:
Is this intentional behavior...

Probably intentional.

...that can be relied on continuing in future versions of the ArduinoIDE...

I rely on it. If you are especially cautious, this will trigger an error if LOW is redefined to a non-zero value...

#if LOW != 0
#error LOW assumed to be 0
#endif

...or is this a misfeature that may be corrected at some point breaking code written to exploit this behavior?

I doubt it.

Also, for code optimization, what creates the smallest binary and/or uses the least clock cycles?

Trust the compiler. It does the right thing most of the time.

In other words, use the one that you will understand six months from now. That is the correct choice.

Thanx to all for all the quick and informative responses.

PaulS:

I've experimented and found that the result of a DigitalRead (result HIGH or LOW) acts as the boolean values TRUE and FALSE. For example:

HIGH is a constant, valued 1. LOW is a constant, valued 0.

TRUE is a constant, valued 1. FALSE is a constant, valued 0.

In C, false is 0, and true is anything but 0.

That is what I thought, but the online reference at arduino.cc doesn't make this clear.

Is this intentional behavior that can be relied on continuing in future versions of the ArduinoIDE, or is this a misfeature that may be corrected at some point breaking code written to exploit this behavior?

It is reasonably certain that nothing will change. One should NOT rely on that, though. It is not that difficult to type:

if(digitalRead(somePin) == HIGH)

making the meaning EXPLICITLY clear, compared to

if(digitalRead(somePin))

Well, because I think more like a EE than a CE, I tend to think of boolean logic as discreet logic gates on a schematic. So when looking at my schematic and I see the signal to a pin is low active I automatically think that the check for an active signal as the statement "NOT pin" instead of the question "is this pin LOW?". (And then add a comment that the signal is low active to remind myself when reading through the source at a later date without the schematic handy...) Similarly, I'm more apt to use INPUT_PULLUP when defining digital inputs than clutter up my schematic and BOM part count with pull up/down resistors for switch type sensors...

Different stroke for different folks.

I agree with PaulS that it's bad practice in general to rely on the actual value of constants, or any other aspect of an component that is not specified as part of the external interface, even though we know that in the specific case of Arduino the HIGH and LOW constants are unlikely ever to change. I mean, it would be daft to change them, wouldn't it?

Almost as daft as Arduino changing the name of their top level include files and making every previous sketch and library invalid. So yeah, obviously HIGH and LOW are never going to change.

Even so, it's not a good idea to assume that digital inputs are active high - arguably, they're more likely to be active low since the Arduino has pull up resistors - it is better to show that relationship explicitly within the sketch.

PeterH:
I agree with PaulS that it's bad practice in general to rely on the actual value of constants, or any other aspect of an component that is not specified as part of the external interface, even though we know that in the specific case of Arduino the HIGH and LOW constants are unlikely ever to change. I mean, it would be daft to change them, wouldn't it?

Almost as daft as Arduino changing the name of their top level include files and making every previous sketch and library invalid. So yeah, obviously HIGH and LOW are never going to change.

I take your point, but... Changing name of top level includes is an environment organizational change, where as HIGH = TRUE and LOW = FALSE are industry standards for TTL and CMOS logic.

Even so, it's not a good idea to assume that digital inputs are active high - arguably, they're more likely to be active low since the Arduino has pull up resistors - it is better to show that relationship explicitly within the sketch.

But the relationship exists explicitly in the schematic. For example, see my attached schematic.

In1 and In4 are both active high, and In2 and In3 are both active low (indicated by the line over the label). In1 and ~In2 are both switches to ground, so I need to provide a pull up in the Arduino. In3 and In4 are both driven outputs from an IC, so I don't need any pull ups or pull downs. Thus, to create a sketch for this circuit that would light the LED on the corresponding output (i.e. In1 => Out1, In2 => Out2, etc) based on whether the signal is "active", I would probably use something like this (the comments are as I would write them for myself...):

const int In1 = 2;
const int In2 = 3;
const int In3 = 4;
const int In4 = 5;
const int Out1 = 8;
const int Out2 = 9;
const int Out3 = 10;
const int Out4 = 11;

void setup() {
  // Input pins
  pinMode(In1, INPUT_PULLUP);  // Switch to ground, no external pull up
  pinMode(In2, INPUT_PULLUP);  // Switch to ground, no external pull up
  pinMode(In3, INPUT);         // IC driven signal
  pinMode(In4, INPUT);         // IC driven signal
  // Output pins
  pinMode(Out1, OUTPUT);
  pinMode(Out2, OUTPUT);
  pinMode(Out3, OUTPUT);
  pinMode(Out4, OUTPUT);
}

void loop() {
  if(digitalRead(In1)) {   // Active high input
    digitalWrite(Out1, HIGH);
  }
  else {
    digitalWrite(Out1, LOW);
  }
  if(~digitalRead(In2)) {  // Active low input
    digitalWrite(Out2, HIGH);
  }
  else {
    digitalWrite(Out2, LOW);
  }
  if(~digitalRead(In3)) {  // Active low input
    digitalWrite(Out3, HIGH);
  }
  else {
    digitalWrite(Out3, LOW);
  }
  if(digitalRead(In4)) {   // Active high input
    digitalWrite(Out4, HIGH);
  }
  else {
    digitalWrite(Out4, LOW);
  }
}

Depending on my mood (and the complexity of the sketch) I may add a H or L to the end of variable names to remind myself of the pin's active state, and only have the comment about active high or low at the variable declaration part.

Again, the method you seem to be promoting (i.e. using a comparison to create a boolean value to check state instead of taking the state directly as a boolean value) is by no means incorrect. It's just extraneous to my thought processes. For example, when looking at a red light (for those of us not colorblind...): when you see the light do you first think "that light is a color" and then "is that color red?", or do you just think "that light is red"? I just think there is space for both of us to be correct.

In1 and In4 are both active high

I'm not sure what you mean by "active high". If you enable the internal pullup resistor, the pin will be HIGH until the switch is pressed. Then it will go LOW.

  if(digitalRead(In1)) {   // Active high input
    digitalWrite(Out1, HIGH);
  }
  else {
    digitalWrite(Out1, LOW);
  }

I don't like this code because it isn't absolutely clear that you know that the pin is HIGH unless the associated switch is pressed. I'm a fan of removing ambiguity whenever possible.

I just think there is space for both of us to be correct.

There is. As long as you agree that I'm more right. 8)

Seriously, not relying on HIGH == true == 1 and LOW == false == 0 is better, in my opinion.

PaulS:

In1 and In4 are both active high

I'm not sure what you mean by "active high". If you enable the internal pullup resistor, the pin will be HIGH until the switch is pressed. Then it will go LOW.

I don't think you understand the schematic fully. Both the switch name (SW_PUSH_NC) and the graphic for SW1 indicate a normally closed switch, so normal conditions is the pin is shunted to ground (low). When the switch is activated, it breaks connection to ground and then the pin floats unless there is a pull-up resistor (which I did activate in pinMode() for In1) to pull it to VCC (high). This is a common configuration for emergency or fault stop switches.

Active high on inputs simply means "there is a signal worth acting on when the voltage at the pin is closer to my supply voltage than the trigger voltage for a logic1 as defined by my logic technology". (I had to use referential terms there because ECL is weird with a negative supply voltage so logic1 is actually lower voltage than logic0. But now a days ECL is considered a special case situation.) For most 5V TTL circuits this is greater than 2V, for most CMOS circuits this is greater than %70 of the supply voltage. See Logic level - Wikipedia (Yes, I know wikipedia says the threshold voltage for CMOS is 50%, but the actual trigger voltages are closer to 30% for low and 70% for high for noise resistance.)

  if(digitalRead(In1)) {   // Active high input

digitalWrite(Out1, HIGH);
  }
  else {
    digitalWrite(Out1, LOW);
  }



I don't like this code because it isn't absolutely clear that you know that the pin is HIGH unless the associated switch is pressed. I'm a fan of removing ambiguity whenever possible.

First, look at the schematic. The pin is LOW unless the associated switch is pressed. (Honestly, did you look at it and understand it?) Second, as I mentioned for more complicated sketches I'd probably put the active level as part of the variable name. Self-documenting variable names are as important as comments. (You do agree with me on that, right? :wink: )

I just think there is space for both of us to be correct.

There is. As long as you agree that I'm more right. 8)

That part I don't agree with. I'm more thinking that we are equally right. :stuck_out_tongue: Agree to disagree? O:) {What... two smiley devils, and no smiley angels?}

Seriously, not relying on HIGH == true == 1 and LOW == false == 0 is better, in my opinion.

But that is the industry convention for TTL and CMOS logic. If software doesn't follow industry convention it is broken and needs to be fixed for wide acceptance. (Ever wonder why HIGH == true == 1 and LOW == false == 0... It wasn't arbitrary...)

This is just one example of an API returning magic numbers and coders relying on what the values of those magic numbers are.

Sure, it's pretty harmless in this case but it is poor practice and the more this practice is applied in other situations the worse the risk of code breaking for obscure reasons, or not being portable.

(There is a related issue of using the wrong types, and the Arduino runtime has a pretty poor track record there too. It makes almost no use at all of abstract typing and doesn't provide any type safety.)