I think many communication subtleties are lost in the written language.
I do appreciate the humor. And I think our thoughts and reasoning
are actually not very far off from each other.
@berrybap: although I agree that one should not rely to much on implementation details I disagree with you reasoning.
1) Please notice that smilies indicate humor.
2) You write
(Udo: All the examples that use exclusive ORing, would break if LOW was not 0)
. This is not true. For which values of HIGH and LOW would this
digitalWrite(pin, state^= (HIGH^LOW));
break?
After going back and looking closer, I admit I was very wrong on this point.
This method is quite clever and generates the least amount of code
of all the working portable examples.
3) You seem to pick this up intentionally. IMHO teaching your "IF" style is no better. It promotes an imperative style and it does not consistently deal with undefined values. Notice: not your code example but the IF style.
For myself, I don't prefer any method over any other, it is just that when trying to explain to person that is struggling
with understanding the basics such as an if/else construct, my suspicion is that it would be easier to help them
grasp an if/else methodology rather than introduce a new/additional language details such as bit twiddling or
ternary operators.
Now probably the real answer is to explain that if/else is one of many solutions and show other examples
that also work, but may use some syntax that they may be less familiar with.
And for completeness maybe even toss in an example that may also work but isn't fully portable.
4) There is not intrinsic API documentation for the Arduino. All documentation is outside Arduino.h. If you look into the header file you will immediately notice that the signatures are flawed:
void digitalWrite(uint8_t, uint8_t);
int digitalRead(uint8_t);
digitalRead delivers values of a different type than its counter part digitalWrite. At no place in the file is there any hint that the macros "HIGH" and "LOW" are to be used with these functions they are not even placed closely. So how would anyone correctly abstract from such an API?
Thus you refer to external "API specification". But which one? As it is this API requires developers to look up the code.
From the prototypes they would have to look at the code.
But that is generally the case with prototypes as they don't convey
information about the API itself only the parameters and return values.
This is why I like using doxygen for the documentation.
That way you can generate pretty documentation like HTML, and
yet still have the same documentation information in the actual code for those
that like to look at code.
From these pages, a developer could write working code.
http://arduino.cc/en/Reference/digitalWritehttp://arduino.cc/en/Reference/digitalReadWhich I'm guessing is what the majority of Arduino users are going by
rather than going in and actually looking at the underlying code.
And if all you have to go by is the reference pages, then you would want
to stick to using HIGH and LOW as the reference indicates.
However, it is not uncommon for API functions in C to be somewhat asymmetric in parameters vs return values.
While some call it sloppiness, it can be useful in some situations.
In some cases the return values from functions that return data are overloaded with status information.
In those cases, return values that land outside the range of the data are error/satatus codes.
Consider the stdlib functions getchar() and putchar().
The return value from getchar() is more than just a character it can also indicate an error.
Likewise the return from the read() function in the serial class uses this as well.
5) Your API example with PWM extensions is completely made up. Typically the method/function names should hint at their use. Extending functions that are prefixed with "digital" to allow for PWM seems not like a reasonable API extension to me. It actually changes the API semantics.
Of course it is made up. I even said as much.
However, I don't believe modifying digitalWrite() to support PWM would
really be changing the semantics as it still is creating a digital signal on a pin.
PWM creates a digital signal not an analog voltage.
It just isn't a signal that is a locked at a single level.
Yes PWM can be used to generate an analog voltage with some
additional components, but PWM itself, is still a digital signal.
analogWrite() is the call that is really messed up.
It does not create an analog level signal at all.
To me analogWrite() is what is misleading.
It hints at "analog" yet generates digital pulses.
The only reason that I bring up the digitalWrite() PWM example with HIGH and LOW
is that if you project Arduino out into the future to the point where you want to run it
on a micro controller that supports REAL analog outputs then the
existing digitalWrite()/analogWrite() API starts get a bit messy and confusing.
Should the day ever come where you need to support both PWM and real anlog output,
you will have to somehow resolve the difference between PWM output and real analog voltage output.
Having a call like analogWrite() complicates things in that it isn't really analog but digital PWM.
If, the digitalWrite() could encompass both steady state levels and PWM, then analogWrite() could
be used for real analog outputs.
And if you think about it, HIGH is no different than an PWM signal of 100% duty cycle
and LOW is no different than a PWM signal of 0% duty cycle.
So combining HIGH/LOW and PWM into a single API function
isn't that far fetched since they already essentially the same thing.
But in order to make a change like this requires everyone to use LOW/HIGH vs 0/1 or 0/non-zero
for digitalWrite().
Now does my craziness seem to make a bit more sense?
6) The "?" Operator is not a macro. It is an operator. IMHO the use of this operator should be more widely understood.
Totally agree.
I use it quite often.