View Issue Details Jump to Notes ] Issue History ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0010233FPCCompilerpublic2007-11-21 23:202008-04-13 16:38
ReporterPeter Popov 
Assigned ToJonas Maebe 
PrioritynormalSeveritymajorReproducibilityalways
StatusclosedResolutionfixed 
PlatformOSOS Version
Product Version2.2.0Product Build 
Target VersionFixed in Version2.4.0 
Summary0010233: ByteBool(i) always converts to numerical value of 1
Descriptionthe following code:

var
  i: Byte;
begin
  i := 2;
  Writeln(Bytebool(i);
end.

will print 1. Instead, it should print 2. In other words, conversion of byte variablt to ByteBool always sets the value to 1.
TagsNo tags attached.
FPCOldBugId
Fixed in Revision9898
Attached Files

- Relationships
related to 0010613closedJonas Maebe D7 compatibility & COM: WordBool incompatibility 
has duplicate 0014150closedJonas Maebe Sometimes ByteBool assignments do not preserve numerical values, related to 0010233 
related to 0011058closedMichael Van Canneyt Wrong type for xlib TBool in trunk 

-  Notes
(0016255)
Peter Popov (reporter)
2007-11-21 23:35

Sorry, code should look like this:

var
  i: Byte;
begin
  i := 2;
  Writeln(Byte(ByteBool(i)));
end;
(0016260)
Marco van de Voort (manager)
2007-11-22 10:41
edited on: 2007-11-22 10:43

???

Afaik a bytebool returns true or false, but on different ranges then a boolean. (C vs Pascal boolean definition)

So boolean(2) is undefined, and bytebool(2) is true (1)

Delphi seems to crash when printing a bytebool

(0016283)
Peter Popov (reporter)
2007-11-23 05:06

Here is the issue:

An ordinary Boolean in TP/DELPHI can assume only ordinary values of 0 and 1. So, for example
var
  a:array[boolean] of something; (Delphi allows this declaration)
is equivalent to
  a:array[0..1] of something;

In contrast, ByteBool, WordBool, LongBool in delphi follow the definition of bool in C/C++: if the ordinal value is 0, the expression is False, otherwise it is true. So, an ordinal value of 2 is just as TRUE as a value of 1. This was probably done for DLL compatibility with win32 functions (preserving the strong type-casting of pascal). However, the nice thing about ByteBool is that it allows recursive/stack use of a boolean flag. For example some operation increments a bytebool var and a nested operation increments once more. then you need to decrement twice before the thing becomes false. so you can use it in stack fashion. I have done this in both Delphi2, Delphi 5 and Kylix 3. In all of those, the following will print 2 (make sure you have compiled a console application otherwise it will crash with I/O 103 due to writeln and no console output):

var
  i: Byte;
begin
  i := 2;
  Writeln(Byte(ByteBool(i)));
end;

FPC will print 1. I think that allowing arbitrary ordinal assignments to a bytebool/wordbool value keeps the spirit of C/C++ bools and the strong type-casting of Pascal. So aesthetically it is nice.
(0016303)
Florian (administrator)
2007-11-23 19:46

I'am against fixing this, I consider this issue implementation specific or undefined whatever you wish ;)
(0016308)
Peter Popov (reporter)
2007-11-23 21:05

Well consider this: suppose you have a C/C++ dll which has a function that returns WordBool (the standard bool in C). Then another function in that DLL takes the output of the first and does something. This function may actually typecast to int or the argument may be altogether an int and do specific actions depending on the ordinal value. So, if this is done within C/C++ the ordinal value will be preserved and no problems will occur. If you call these two functions from FPC a problem will occur - the second function will always get 0 or 1. So it is actually a portability issue. I beleive this is why these three types (ByteBool, WordBool and LongBool) were introduced in Delphi in the first place.
(0016309)
Florian (administrator)
2007-11-23 21:15

This is nowhere defined. This is pure luck that it works sometimes this way.
(0016310)
Peter Popov (reporter)
2007-11-23 21:55

Look, two things: it is easier and faster if you just assign the ordinal value, instead of setting it to 1 (you have to make a test if it is nonzero). Second, the world is a big place and all sorts of programming practices, good or bad exist. I think you will get the most portability if you treat it as an arbitrary ordinal value. Essentially all C code works this way (there is no stantard bool, false is a zero test of an integer variable) and you won't loose anything if you increase portability.

Please don't get me wrong: I am not trying to tell you how to make your compiler nor am I bugging you to fix a delphi incompatibility issue just for the sake of Delphi compatibility (I assume you want your own compiler, not a borland clone), nor do I advocate C. I noticed this because I am porting some delphi code that interacts with C shared libraries. So I reported it as a bug. I was lucky to notice the issue quickly. Some poor soul may spend days figuring this thing and then end up cursing the whole world.

Out of curiosity, if you force via assembler a bytebool var to a value of, say 10, what will then a true/false test give on this variable in FPC?
(0017257)
Jonas Maebe (manager)
2008-01-13 16:50

Bytebool is really ugly in Kylix:

begin
  writeln(sizeof(bytebool));
  writeln(int64(high(bytebool)));
  writeln(int64(low(bytebool)));
end.

results in

1
2147483647
-2147483648

Yes, a type of 1 byte large which stores 32 bit values... Adding this to FPC will probably result in quite a few ugly hacks to work around sanity checks and assumptions that situations like the above are not possible.

It does show that byte/word/longbool are handled specially by Kylix though, and that the implementation details probably are intentionally that way...
(0017259)
Florian (administrator)
2008-01-13 17:54

I don't see what's intentional, the docs are rather clear about it.
(0017260)
Jonas Maebe (manager)
2008-01-13 18:32
edited on: 2008-01-13 22:11

When looking at http://www.thescripts.com/forum/thread220664.html [^] , there's a print of a table which says (a.o.):

* for boolean: False < True
* for byte/word/longbool: False <> True

* for boolean: Pred(True) = False
* for byte/word/longbool: Pred(False) = True

The last statement currently gives a range check error in FPC, because -1 is not considered a valid value for byte/word/longbool. Combined with the fact that also "Succ(False) = True" and "False <> True" (as opposed to "False < True" for booleans) for byte/word/longbool, I think this makes it clear that "True" can be any ordinal different from False rather than just "1".

Then there is the issue mentioned in 0010613 that COM apparently requires that True=-1, and several pages (e.g. http://safari.oreilly.com/0672321157/ch04lev1sec7 [^] and http://discuss.joelonsoftware.com/default.asp?joel.3.355854.11 [^] ) mentioning that byte/word/longbool were introduced exactly for this reason.

So changing (e.g.) -1 into 1 when getting the ordinal value of a byte/word/longbool does not seem advisable to me.

Edit: the safari.oreilly.com link only shows interesting content if you come from Google, so go to http://www.google.com/search?hl=en&q=bytebool+wordbool+longbool+site%3Asafari.oreilly.com&btnG=Search [^] and click on the first link

(0017267)
mspiller (reporter)
2008-01-14 12:46
edited on: 2008-01-14 12:54

Probably the reason why integer types of boolean are defined as 0 and $ff is because it is faster for not operator.
asm not:
not 0 = $ff
not $ff = 0

If you want to have ms compatible variant you must use $ffff for true as described in http://msdn2.microsoft.com/en-us/library/ms221627.aspx. [^] It explicitly forbids any other value than 0 and $ffff for boolean type. Otherwise it provides compatibility problems as shown in bug 0010613 with msxml.

(0017269)
Jonas Maebe (manager)
2008-01-14 13:19

FWIW, for 0 and 1 you can use "xor 1" as "not" operator (which is also a single assembler instruction, and what we currently do).

The $ffff would be for wordbool (and VT_BOOL parameters would have to be declared as wordbool). For bytebool it's $ff and for longbool it's $ffffffff.

And I guess the reason the range of bytebool and wordbool is low(longint)..high(longint) in Kylix is to enable assigning a longbool to a bytebool without getting a range check error.
(0017310)
Peter Popov (reporter)
2008-01-17 09:57

In my opinion, when $R-, the best way to resolve this is to preserve the ordinal value of any assignment/typecast to a bytbool (wordbool) variable. This will ensure compatibility with whatever external dlls/activeX code (and associated semantics) one is using. With respect to OLE/ActiveX, one may define TRUE (i.e. the assignment b := TRUE, where b: ByteBool/WordBool) as $FFFF, or, make it switch dependent (1 or $FFFF). It is essential though to preserve the ordinal value.

If, on the other hand, range checking is on, the most logical thing IMO is to treat ByteBool as something with a single byte range and WordBool as something with a 2 byte range. It remains a question what to do with pred/succ of such a variable. The two reasonable logical alternatives are that (i) pred(..) and succ(...) should either treat their argument as byte/word respectively or (ii) alternatively be prohibited from operating (at compile time) on bytebool and wordbool. I agree that the kylix pred/succ implementations is not in the spirit of the pred/succ semantics.
(0017339)
Jonas Maebe (manager)
2008-01-19 15:45
edited on: 2008-01-19 17:42

Things get even better: in TP, byte/word/longbool had different behaviour. Not for the submitted example, but for things like this:

var
  b: bytebool;
begin
  b:=true;
  writeln(byte(b));
end.

The above prints 1 in TP, but 255 in Kylix. We can emulate this depending on the current language mode, but the question then becomes: what do we do in FPC and ObjFPC modes? Remain backwards compatible with TP/FPC and keep "true=1" in all cases, or change the behaviour to be Delphi compatible so true=-1 for byte/word/longbool?

Edit: actually, doing it differently in different modes is not good, because you can call routines compiled in a different mode from the current mode. That could lead to quite annoying bugs, due to one bunch of routines expecting and producing 0&1 and another 0&<>0 (or to lots of unnecessary conversion code to ensure that the true value is always the expected one for the current mode).


- Issue History
Date Modified Username Field Change
2007-11-21 23:20 Peter Popov New Issue
2007-11-21 23:35 Peter Popov Note Added: 0016255
2007-11-22 10:41 Marco van de Voort Note Added: 0016260
2007-11-22 10:43 Marco van de Voort Note Edited: 0016260
2007-11-23 05:06 Peter Popov Note Added: 0016283
2007-11-23 19:46 Florian Note Added: 0016303
2007-11-23 21:05 Peter Popov Note Added: 0016308
2007-11-23 21:15 Florian Note Added: 0016309
2007-11-23 21:55 Peter Popov Note Added: 0016310
2008-01-12 17:46 Jonas Maebe Relationship added related to 0010613
2008-01-13 16:50 Jonas Maebe Note Added: 0017257
2008-01-13 17:54 Florian Note Added: 0017259
2008-01-13 18:32 Jonas Maebe Note Added: 0017260
2008-01-13 22:11 Jonas Maebe Note Edited: 0017260
2008-01-14 12:46 mspiller Note Added: 0017267
2008-01-14 12:54 mspiller Note Edited: 0017267
2008-01-14 12:54 mspiller Note Edited: 0017267
2008-01-14 13:19 Jonas Maebe Note Added: 0017269
2008-01-17 09:57 Peter Popov Note Added: 0017310
2008-01-19 15:45 Jonas Maebe Note Added: 0017339
2008-01-19 15:45 Jonas Maebe Status new => assigned
2008-01-19 15:45 Jonas Maebe Assigned To => Jonas Maebe
2008-01-19 17:42 Jonas Maebe Note Edited: 0017339
2008-01-24 22:31 Jonas Maebe Fixed in Revision => 9898
2008-01-24 22:31 Jonas Maebe Status assigned => resolved
2008-01-24 22:31 Jonas Maebe Fixed in Version => 2.3.1
2008-01-24 22:31 Jonas Maebe Resolution open => fixed
2008-03-28 16:36 Jonas Maebe Relationship added related to 0011058
2008-04-13 16:38 Jonas Maebe Status resolved => closed
2009-07-16 07:57 Jonas Maebe Relationship added has duplicate 0014150



MantisBT 1.2.12[^]
Copyright © 2000 - 2012 MantisBT Group
Powered by Mantis Bugtracker