gnustep-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [RFA]: BOOL coding standards (Was: Problemwith+numberWithBool:?)


From: David Ayers
Subject: Re: [RFA]: BOOL coding standards (Was: Problemwith+numberWithBool:?)
Date: Tue, 10 Feb 2004 12:44:01 +0100
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040113

Kazunobu Kuriyama wrote:

Pascal J.Bourguignon wrote:

Kazunobu Kuriyama writes:

So I'm wondering if changing the expression to
[NSNumber numberWithBool: isYES(i=256)];
or something like this always gives the right answer. Sometimes it is, but
what if generating NO is the coder's genuine intention?



Then it was obscure code. He should have made his intention explicit
and he shoudl have written:

[NSNumber numberWithBool: (((i=256)&0xff)!=0)]

confident that the compiler would have generated EXACTLY the same code
(at least with -O3).


I am thoroughly sorry for having introduced such a misleading example to express my intention. The original issue was that comparing BOOL variables/return values with '== YES' could be considered unsafe, *if* one argued that all expressions which C evaluates to true in if/while/for tests should be interpreted as valid BOOL values to be interpreted as "!= NO". The macro isYES() originally was meant as a replacement for "== YES" to allow all non NO values to interpreted as YES.

The misleading example was meant to show that certain expressions that returned values that if/while/for tests would correctly evaluate to true, where the same expressions passed as a parameter expecting a BOOL or assigned to a BOOL variable will be assigned NO. It was by pure laziness and lack of creativity that I embedded an assignment into the method dispatch. Nicola and Manuel cited much better examples.

Let's take the embedded function example:

int isupper (int c);
   checks for an uppercase letter.
RETURN VALUE
   The values returned are nonzero if the character c falls
   into the tested class, and a zero value if not.

based on this, isupper could return an integer who's lower byte happened to be clear, yet still returns a non-zero value.

Therefore [NSNumber numberWithBool: isupper(c)] is unsafe code.

Remember that my original suggestion of using isYES() entailed that numberWithBool: could use:

#define isYES(_exp) ((_exp) != NO)
- (id)numberWithBool:(BOOL)val
{
 val = isYES(val);
 return [[self alloc] initWithBool:val];
}
to "BOOLify" the parameter (i.e. (more or less silently) interpret all non-NO values as YES). But in the case that isupper() happened to return 256, val would be 0 and therefor would return an unexpected NSNumber object. The implementation of numberWithBool: has no chance of rectifying this.
I think one of the present problems is to answer the question whether or
not the proposed macro can correctly fix such existing code (without
any unexpected cost if possible), not to give the code an ethical/aesthetic
evaluation.

The macro can't fix it in the callee. The caller must insure it supplies a correct value. Which brings us to Richards suggestion to instead use a macro to assert that the caller has supplied valid BOOL values of either YES or NO to potentially detect code where the caller didn't take care to pass an explicit BOOL values. (Note, that the case above where the caller supplies a value who's lower byte happens to clear by chance will not and cannot be detected.) We would only detect the cases where we /could/ reinterpret the value to YES, but the point of the macro would be to warn/assert about the invalid value.

So this macro has a very different purpose than my isYES() proposal which was simple replacement for '== YES' as I falsely thought it would make code using it more robust. What we are discussing now is a macro to warn/assert about non-YES/NO BOOL values. This macro does not intend to "rectify" wrong BOOL values but to indicate invalid BOOL usage. Yet we may choose to warn /and/ "rectify" where possible as a side effect to give people time to fix their code. (And as this macro is not a '== YES' replacement anymore, I'd really like to give it a different name not focused on YES, and I agree with Richard that _is() seems the least bulky while it is a little less likely to conflict with user code than is().)

Cheers,
David

If we have to pay attention to semantics defined by ourselves as well as syntax, I'm afraid it makes the maintenance of code harder because we have to take two possible interpretations into consideration and decide which is the coder's intention. Furthermore, it unexpectedly reduces the readability
of code when semantics and syntax respectively give contradictory
interpretations.



In any case,

[NSNumber numberWithBool: i=256]

is much less readable than:

[NSNumber numberWithBool: (((i=256)&0xff)!=0)]

which itself is much less readable than:

i=256;
[NSNumber numberWithBool: NO]

(Here you see another "stylistic" rule in my book: never use
assignation in expressions, only in statements, and one at a time);


I was not talking about this sort of readability, or readability for
human being.  What I meant was whether or not a given expression yields
a consistent interpretation to which both we and compilers can agree.
If the syntax-based interpretation of some code differs from the
corresponding sematics-based one, we can call the code unreadable as
well.

We human being read code primirily based on semantics, but our poor
compilers do it only relying on syntax (or, they don't know any other
way). This discrepancy is just what I'm worrying about. IOW, introducing
user-defined semantics that compilers don't exactly know is dangerous;
therefore, we should be prudent in doing it.


PS: I think I failed to comprehend the point above. I don't intend to introduce a macro that translates a semantic interpretation into a syntactically different code. If this is somehow still relevant, may I please ask you to rephrase it.





reply via email to

[Prev in Thread] Current Thread [Next in Thread]