Adriaan van Os wrote:
Use an integer or cardinal type instead (for example in the Win32 API, but that API is a mess anyway, dependent on the call you have to check for <> 0 or = 0 or <> 1 or =1).
I don't know this API. Do you mean there are functions where 0 means False, 1 means True, but 2, 3, ... means False? (Or vice versa?) Ouch!
Some examples (but I have seem more weird cases)
SystemParametersInfo <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ sysinfo/base/systemparametersinfo.asp> If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError.
So that's <> 0, fine.
SHGetPathFromIDList <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ wceshellui5/html/wce50lrfshgetpathfromidlist.asp> TRUE indicates success. FALSE indicates failure.
Assuming FALSE = 0 and TRUE = 1 or some other value <> 0, and no other return values are possible, that's also fine with <> 0.
DeviceCapabilities <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/ prntspol_21bn.asp> If the function succeeds, the return value depends on the setting of the fwCapability parameter. A return value of zero generally indicates that, while the function completed successfully, there was some type of failure, such as a capability that is not supported. For more details, see the descriptions for the fwCapability values. If the function fails, the return value is -1.
Is this description complete? -1 is failure, 0 is "generally [...] some type of failure"? Then > 0 is success, or what? Since -1 and 0 "generally" seem to have to be distinguished, that's just not a Boolean (two-valued) result, so one should just use an integer result type.
I'd yet have to see the weirder cases, but so far I see no problem. Perhaps there are perceived problems when not all results are possible.
There's a similar situation with some POSIX routines that return a file descriptor or some other value guaranteed >= 0 when successful and -1 (as documented) on failure. Some C programmers seem to believe they have to test for == -1 for failure. But actually, since values < -1 cannot occur at all according to the documentation, checking < 0 for failure is just as good -- probably even better since getting an "impossible" value < -1 would really be a serious failure (and apart from the fact that < 0 is both shorter to write and often generates easier machine code than == -1).
(I don't mean that these are Boolean results -- clearly not, since values >= 0 must be distinguished --, but that sometimes one sees things more complicated than necessary by reading documentation too literally.)
Hm, now that I have written this down, I start to wonder if "boolean attribute ..." wasn't invented to be compatible with the Win32 API. I had a look at the Borland Delphi 3 Object Pascal Language Guide (page 4-5 to 4-6).
Not particularly the Win32 API, but generally external interfaces, yes. After all, for usage within Pascal code, we don't need specific storage requirements.
"Boolean types There are four predefined Boolean types: Boolean, ByteBool, WordBool and LongBool. Boolean values are denoted by the predefined constant identifiers False and True. Because Booleans are enumerated types, these relationships hold:
Boolean ByteBool, WordBool, LongBool False < True False<>True Ord( False) = 0 Ord( False) = 0 Ord( True) = 1 Ord( True) = any non-zero value Succ( False) = True Succ( False) = True Pred( False) = True Pred( False) = True "
(I wonder if the last line isn't a printing error meant to say Pred( True) = False)
Yes, the last line is strange. The right side would hold for extended Boolean types with negative ordinal values, or with wrap-around without overflow checking (which isn't exactly something I'd make documented behaviour).
OTOH, Pred (True) = False is right for standard Boolean, but not for extended Booleans when calling any non-zero value "True" as they do.
A Boolean variable can assume the ordinal values 0 and 1 only, but variables of type ByteBool, WordBool and LongBool can assume other ordinal values.
I think that's the main point. So for compatibility, it seems we should extend the range of the larger Boolean types. The predefined value "True" would, of course, still yield ordinal 1, but an extended Boolean might function as "true" in conditionals, but have Ord (...) > 1 (or < 0 if we'd allow for "signed" types, but so far I see no need to).
An expression of type ByteBool, WordBool or LongBool is considered False when its ordinal value is zero, and True when its ordinal value is nonzero.
So clearly <> 0, which GPC already does (being derived from C, no surprise).
Whenever a ByteBool, WordBool or LongBool value is used in a context where a Boolean value is expected, the compiler will automatically generate code that converts any nonzero value to the value True."
GPC does this (actually kind of inadvertently -- AFAIR, the respective code was added to avoid type and/or range problems in such conversions, but it does just that). To be sure, I'm adding the following test program:
program fjf1102 (Output);
var a: ByteBool; b: WordBool; c: LongBool; d, e, f: Boolean;
begin a := ByteBool (42); b := WordBool (1000); c := LongBool ($10000); d := a; e := b; f := c; if (Ord (d) = 1) and (Ord (e) = 1) and (Ord (f) = 1) then WriteLn ('OK') else WriteLn ('failed ', Ord (d), Ord (e), Ord (f)) end.
Looks like, for compatibility, we have to distinguish clearly between the Pascal Boolean type and C-derived "integer" booleans, for example:
ByteBool = IntBoolOfBitSize (8) WordBool = IntBoolOfBitSize (16) LongBool = IntBoolOfBitSize (32)
again deprecating "boolean attribute ..."
Yes, seems so.
And now it gets really weird ...
type VeryTrue = ByteBool (10) .. ByteBool (42);
Frank