likely bug in FPC v3.2.2 handling of booleans lazarus / 67-Windows ---------------------------------------------------------------------- 440bx · 2025-01-28 06:10 Hello, Consider the following program:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$MODE OBJFPC } program BooleanBug; function TestBoolean() : boolean;var  b8   : Boolean   = FALSE;  b16    : Boolean16 = FALSE;   BooleanArray : bitpacked array[0..1] of boolean = (FALSE, FALSE); begin  ord(b8)  := 4;                // true  ord(b16) := 8;                // true   writeln('ord(b8)  = ', ord(b8));  writeln('ord(b16) = ', ord(b16));  writeln;   { --------------------------------------------------------- ---------------- }   // assign the variables to the bitpacked elements  // both, b8 and b16 are supposedly true but, when assigned to a bitpacked  // boolean, one of them is no longer true.   BooleanArray[0] := b8;  writeln('b8  = ', b8,  ' ord(b8)  = ', ord(b8),  ' BooleanArray[0] = ', BooleanArray[0]);  BooleanArray[1] := b16;  writeln('b16 = ', b16, ' ord(b16) = ', ord(b16), ' BooleanArray[1] = ', BooleanArray[1]);  writeln;   result := true;end; begin  TestBoolean();end. The output shows that the first array element is FALSE and the second array element is TRUE.  Both elements should be the same, not one TRUE and the other one FALSE. Since the compiler considers them both to be TRUE, it follows that the array elements should also both be TRUE. Comments welcome. ---------------------------------------------------------------------- Thaddy · 2025-01-28 07:28 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   ord(b8)  := 4;                // true  ord(b16) := 8;                // trueReally? Both must be false. It is legal code but it is not an assignment to b8 or b16. For that you need to do something like: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   b8  := Sizeof(b8) = 1;   b16 := SizeOf(b16) = 2; It needs to resolve to either zero or one as per the definition of a pascal boolean. Ord() is an intrinsic function, so creates an intermediate result. It is not "in-place"!!! https://www.freepascal.org/docs-html/rtl/system/ord.html Sorry, no bug. To verify that, add:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i    writeln(low(b8),high(b8));   writeln(low(b16),high(b16)); ---------------------------------------------------------------------- 440bx · 2025-01-28 07:40 Quote from: Thaddy on January 28, 2025, 08:28:29 amSorry, Yes, it is obvious you are rather sorry. Now, if it isn't too much to expect from you, compile and run the program. ---------------------------------------------------------------------- Thaddy · 2025-01-28 07:42 I did, hence I spotted that... Had to take an extra coffee. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i    writeln(low(b8),high(b8));   writeln(low(b16),high(b16)); So you still think it is a bug? ROFL. ---------------------------------------------------------------------- Thaddy · 2025-01-28 07:50 Is it too much to trust me I am almost always right? In the cases I am not it gets blown out of proportions by some. Not a bug. ord is not a cast, which you seem to think. What the hell did you expect from this:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   ord(b8)  := 4;                // true  ord(b16) := 8;                // true   silly. Back to coffee. Have you been out of sleep(0) lately?  Otherwise, why do you expect the result to be different? You know how to use a debugger.... ---------------------------------------------------------------------- cdbc · 2025-01-28 08:01 Hi Hmmmm... Could it be, that you're mistaken 'boolean' for 'bool' or 'longbool'?!? I mean, a 'boolean' in pascal is an enumerated type of (false,true) ~ ord(0..1), whereas 'bool & longbool' are not and with these, 0 = false and 'anything but 0' = true. Just saying... Regards Benny ---------------------------------------------------------------------- Thaddy · 2025-01-28 08:04 No Benny, they are both Pascal booleans defined as range 0..1 - not C bool - but with a different size. I thought the same, though, but the issue is simply that he seems to think Ord() is a cast, whereas it is of course a function. https://www.youtube.com/watch?v=kRwCPUEND1U ---------------------------------------------------------------------- Martin_fr · 2025-01-28 08:12 https://www.freepascal.org/docs-html/ref/refsu4.html They are both zero or one. The values 4 and 8 are out of range. If you assign (to an enum, or subrange value) an out of range value, then the behaviour of the program will be undefined. So, the code you presented may (depending on compiler version, optimization and other settings) give different results. ---------------------------------------------------------------------- Thaddy · 2025-01-28 08:14 Martin, he thinks ord() behaves like a cast... that's all. ---------------------------------------------------------------------- DragoRosso · 2025-01-28 08:26 Quote from: Martin_fr on January 28, 2025, 09:12:25 amhttps://www.freepascal.org/docs-html/ref/refsu4.html They are both zero or one. The values 4 and 8 are out of range. If you assign (to an enum, or subrange value) an out of range value, then the behaviour of the program will be undefined. So, the code you presented may (depending on compiler version, optimization and other settings) give different results. In the document you refers it's said that  QuoteFree Pascal also supports the ByteBool, WordBool, LongBool and QWordBool types. These are of type Byte, Word, Longint or Int64, but are again assignment compatible with a Boolean. These means that if you assign to boolean any value in those ranges, that should be OK, and must be OK. Or I understand wrong ? By the way, I faces to those problems some times ago and by that time I always use WordBool, expecially if other languages, exporting of values (like writing in DB or in a file) are involved. ---------------------------------------------------------------------- Martin_fr · 2025-01-28 08:35 Quote from: DragoRosso on January 28, 2025, 09:26:20 amQuote from: Martin_fr on January 28, 2025, 09:12:25 amhttps://www.freepascal.org/docs-html/ref/refsu4.html In the document you refers it's said that  QuoteFree Pascal also supports the ByteBool, WordBool, LongBool and QWordBool types. These are of type Byte, Word, Longint or Int64, but are again assignment compatible with a Boolean. These means that if you assign to boolean any value in those ranges, that should be OK, and must be OK. Yes, that is right. ---------------------------------------------------------------------- tetrastes · 2025-01-28 09:03 Quote from: Thaddy on January 28, 2025, 09:04:22 ambut the issue is simply that he seems to think Ord() is a cast, whereas it is of course a function. Then why Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ord(b8)  := 4;is compiled at all? You cannot do that with a function: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function BoolToInt(b: boolean): longint;begin    Result := ord(b);end;. . . BoolToInt(b8) := 4; is not compiled with "Error: Argument cannot be assigned to". ---------------------------------------------------------------------- tetrastes · 2025-01-28 09:35 Quote from: 440bx on January 28, 2025, 07:10:37 amThe output shows that the first array element is FALSE and the second array element is TRUE.  Both elements should be the same, not one TRUE and the other one FALSE. Since the compiler considers them both to be TRUE, it follows that the array elements should also both be TRUE. Comments welcome. The question is how boolean is bitpacked? Change Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ord(b8) := 5;and see the result. Or Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i BooleanArray : bitpacked array[0..1] of Boolean16 = (FALSE, FALSE); ---------------------------------------------------------------------- Thaddy · 2025-01-28 09:42 It has nothing to do with bitpacked but the use of ord() ---------------------------------------------------------------------- tetrastes · 2025-01-28 09:51 The results for bitpacked and not bitpacked arrays are different. ---------------------------------------------------------------------- Thaddy · 2025-01-28 10:01 No, not here. which version are you using? Also note he uses the stack... and the stack is dirty. It is simply not a bug, but a perception. You can go on forever, but it does not make sense. There, you have it, didn't do that for months. ---------------------------------------------------------------------- marcov · 2025-01-28 10:34 Basically putting an undefined value in b8 an b16 makes anything that follows uncertain. It seems the code paths for b8 and b16 are slightly different since b16 tests the value with orw   %di,%di setneb   %al So that is a not equal test, not a =1 test. That might indicate a bug, but might also be considered an optimization. ---------------------------------------------------------------------- tetrastes · 2025-01-28 10:58 I don't say that it's a bug. I say that this is because boolean is bitpacked to one bit (simply truncated): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i BooleanArray : array[0..1] of Boolean = (FALSE, FALSE);. . .ord(b8)  := 4;. . .b8  = TRUE ord(b8)  = 4 BooleanArray[0] = TRUE b16 = TRUE ord(b16) = 8 BooleanArray[1] = TRUE SizeOf(BooleanArray) = 2 ord(BooleanArray[0]) = 4 ord(BooleanArray[1]) = 1 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i BooleanArray : bitpacked array[0..1] of Boolean = (FALSE, FALSE);. . .ord(b8)  := 4;. . .b8  = TRUE ord(b8)  = 4 BooleanArray[0] = FALSE b16 = TRUE ord(b16) = 8 BooleanArray[1] = TRUE SizeOf(BooleanArray) = 1 ord(BooleanArray[0]) = 0 ord(BooleanArray[1]) = 1 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i BooleanArray : bitpacked array[0..1] of Boolean = (FALSE, FALSE);. . .ord(b8)  := 5;. . .b8  = TRUE ord(b8)  = 5 BooleanArray[0] = TRUE b16 = TRUE ord(b16) = 8 BooleanArray[1] = TRUE SizeOf(BooleanArray) = 1 ord(BooleanArray[0]) = 1 ord(BooleanArray[1]) = 1 You may also play with bitpacked array of Boolean16: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i BooleanArray : array[0..1] of Boolean16 = (FALSE, FALSE);. . .ord(b8)  := 4;ord(b16)  := 8;. . .b8  = TRUE ord(b8)  = 4 BooleanArray[0] = TRUE b16 = TRUE ord(b16) = 8 BooleanArray[1] = TRUE SizeOf(BooleanArray) = 4 ord(BooleanArray[0]) = 1 ord(BooleanArray[1]) = 8 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i BooleanArray : bitpacked array[0..1] of Boolean16 = (FALSE, FALSE);. . .ord(b8)  := 4;ord(b16)  := 8;. . .b8  = TRUE ord(b8)  = 4 BooleanArray[0] = TRUE b16 = TRUE ord(b16) = 8 BooleanArray[1] = FALSE SizeOf(BooleanArray) = 1 ord(BooleanArray[0]) = 1 ord(BooleanArray[1]) = 0 FPC versions 3.2.2, 3.2.3-1400-g1bcaaacfe4 [2024/09/23], 3.3.1-16887-g7ac4e38b71 [2024/11/12]. ---------------------------------------------------------------------- 440bx · 2025-01-28 12:34 Let's look at the code again (added a few lines to output truth values of the variables): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$MODE OBJFPC } program BooleanBug; function TestBoolean() : boolean;var  b8   : Boolean   = FALSE;  b16    : Boolean16 = FALSE;   BooleanArray : bitpacked array[0..1] of boolean = (FALSE, FALSE); begin  ord(b8)  := 4;                // true  ord(b16) := 8;                // true   writeln('ord(b8)  = ', ord(b8));  writeln('ord(b16) = ', ord(b16));  writeln;   { --------------------------------------------------------- ---------------- }  { have the compiler output how it sees the values of b8 and b16             }   { in both cases it compares the value against 0 to determine if the value   }  { is TRUE or FALSE.  This means that, the compiler is NOT considering 1 as  }  { the value TRUE but, any non-zero value which is NOT what the documentation}  { says the compiler does with Boolean, Boolean16, Boolean32 and Boolean64   }   if b8  then writeln('b8  is TRUE') else writeln('b8  is FALSE');  if b16 then writeln('b16 is TRUE') else writeln('b16 is FALSE');  writeln;   { --------------------------------------------------------- ---------------- }   // assign the variables to the bitpacked elements  // both, b8 and b16 are supposedly true but, when assigned to a bitpacked  // boolean, one of them is no longer true.   BooleanArray[0] := b8;  writeln('b8  = ', b8,  ' ord(b8)  = ', ord(b8),  ' BooleanArray[0] = ', BooleanArray[0]);  BooleanArray[1] := b16;  writeln('b16 = ', b16, ' ord(b16) = ', ord(b16), ' BooleanArray[1] = ', BooleanArray[1]);  writeln;   result := true;end; begin  TestBoolean();end. The writeln statements in line 28 and 29 establish that the compiler chooses to interpret the values of b8 and b16 as TRUE.  This is a choice made by the compiler.  This choice can be clearly seen in the assembly code where the compiler tests both values against zero (0) to determine whether their value is TRUE or FALSE.  Refer to the attachment. Therefore, there can be no doubt that, as far as the compiler is concerned, b8 and b16 are both TRUE.  Fact established by comparing against zero (0) which means that, contrary to the documentation, it is NOT the value 1 that represents TRUE but any non-zero value. The bug is simple, what the compiler considers a TRUE value is being assigned to BooleanArray[0] and to BooleanArray[1], therefore they should both be TRUE but, they are not both TRUE, one is and the other one isn't.  Refer to the output part of the attachment. Based on the documentation, b8 and b16 should both be FALSE since their least significant bit is not set and the value 1 is supposedly the only value that yields TRUE. See "Table 3.4 Boolean types" (which by the way is missing the Boolean8 type.) Essentially, the compiler is _sometimes_ treating b8 and b16 as if they were ByteBool and WordBool respectively and sometimes not.  This can be observed in the assembly code where the value b8 is compared against the value 1 to determine its truth value while the value of b16 is determined by whether or not b16 is non-zero. The inconsistent treatment which is exposed when assigning the values to a bitpacked array is the bug. ---------------------------------------------------------------------- Martin_fr · 2025-01-28 13:36 Quote from: marcov on January 28, 2025, 11:34:35 amBasically putting an undefined value in b8 an b16 makes anything that follows uncertain. It seems the code paths for b8 and b16 are slightly different since b16 tests the value with orw   %di,%di setneb   %al So that is a not equal test, not a =1 test. That might indicate a bug, but might also be considered an optimization. I would consider it optimization. But basically it is a "not zero" test => which is correct to. zero is one of the two allowed values. The interesting difference in asm code happens if you do Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i if mybool1 = bybool2 then If those are "boolean", then they may be binary compared. Meaning that "boolean(2) <> boolean(3)". But if they are e.g. ByteBool then they will be tested as  (or similar) Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   ( ord(mybool1)<>0 ) =  ( ord(mybool2)<>0 ) Meaning a lot more generated asm code. ---------------------------------------------------------------------- Thaddy · 2025-01-28 14:28 Quote from: 440bx on January 28, 2025, 01:34:18 pmBased on the documentation, b8 and b16 should both be FALSE since their least significant bit is not set and the value 1 is supposedly the only value that yields TRUE. Which is what I consistently get on trunk/main, as I already stated. On ARM architectures, I did not test intel/amd. There has been quite some work regarding boolean types in main as opposed to 3.2.2. It may be that the misunderstanding comes from there. Another thing is that platform may be involved: The adagium true is not false may have crept in after all and that is indeed not correct: false-true is 0-1 for Pascal booleans of any type. So the low bit must always be set to be true. If the optimization is such that the value 1 for true is not correctly interpreted then indeed this is a bug, because as Martin wrote, both 4 and 8 should be false since the first bit is false for both. ---------------------------------------------------------------------- Martin_fr · 2025-01-28 17:21 Quote from: 440bx on January 28, 2025, 01:34:18 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  b8   : Boolean   = FALSE;  b16    : Boolean16 = FALSE;  Based on the documentation, b8 and b16 should both be FALSE since their least significant bit is not set and the value 1 is supposedly the only value that yields TRUE. "One is the only one that yields true" is a half truth. Any value that is not one or zero is an undefined value, and can yield (at random) yield either true or false. Hence "One is the only one that can be trusted to yields true" ---------------------------------------------------------------------- Fred vS · 2025-01-28 17:57 Sorry to be a troublemaker but why use the problematic boolean? It's easier to use byte and if result < 1 it's false and if result > 0 it's true. ---------------------------------------------------------------------- TRon · 2025-01-28 18:43 Quote from: Fred vS on January 28, 2025, 06:57:34 pm.. why use the problematic boolean? Sometimes it is not about whether or not the code makes actual sense or a problem could be solved by using other code but how the compiler behaves (under certain conditions). Sometimes the compiler does things that doesn't make sense (at least to me) while it should. Most of the times it is due to a bad interpretation of the documentation or lack thereof but sometimes it is valid to question the behaviour or at least try to get a better understanding of it. In this particular case TS expects the compiler to behave in a certain way while it doesn't seem to do so. Whether or not it should behave the way it seem to do for the example turns into a debate (as living proof this thread) that usually follows when questioning behaviour of the compiler. ---------------------------------------------------------------------- marcov · 2025-01-28 18:58 Quote from: Fred vS on January 28, 2025, 06:57:34 pmSorry to be a troublemaker but why use the problematic boolean? It's easier to use byte and if result < 1 it's false and if result > 0 it's true. Unless you accidentally use a signed expression. So use <>0. ---------------------------------------------------------------------- marcov · 2025-01-28 19:07 Quote from: Martin_fr on January 28, 2025, 02:36:29 pmQuote from: marcov on January 28, 2025, 11:34:35 amIt seems the code paths for b8 and b16 are slightly different since b16 tests the value with orw   %di,%di setneb   %al So that is a not equal test, not a =1 test. That might indicate a bug, but might also be considered an optimization. I would consider it optimization. But basically it is a "not zero" test => which is correct to. zero is one of the two allowed values. I think so that the optimisation bit is defensible too. The question is if that optimisation was intended So it might be worth a bugreport and some tests on other architectures. ---------------------------------------------------------------------- Zoran · 2025-01-28 19:43 Quote from: tetrastes on January 28, 2025, 10:03:11 amQuote from: Thaddy on January 28, 2025, 09:04:22 ambut the issue is simply that he seems to think Ord() is a cast, whereas it is of course a function. Then why Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ord(b8)  := 4;is compiled at all? You cannot do that with a function: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function BoolToInt(b: boolean): longint;begin    Result := ord(b);end;. . . BoolToInt(b8) := 4; is not compiled with "Error: Argument cannot be assigned to". Does anyone knows the answer to this question? Ord() is a function, it is documented to be a function, it is not a cast, however it might be implemented internally. The compiler must not allow direct assignment to a function result, right? ---------------------------------------------------------------------- marcov · 2025-01-28 19:45 Well, ord() is not a function ---------------------------------------------------------------------- Zoran · 2025-01-28 19:51 Quote from: marcov on January 28, 2025, 08:45:25 pmWell, ord() is not a function The documentation says that it is a function. Thaddy is right there. It might be implemented as a cast, but that should be just an implementation detail. This is a bug. At least a documentation bug, but I don't think so. ---------------------------------------------------------------------- Martin_fr · 2025-01-28 19:57 Quote from: marcov on January 28, 2025, 08:07:35 pmQuote from: Martin_fr on January 28, 2025, 02:36:29 pmQuote from: marcov on January 28, 2025, 11:34:35 amIt seems the code paths for b8 and b16 are slightly different since b16 tests the value with orw   %di,%di setneb   %al So that is a not equal test, not a =1 test. That might indicate a bug, but might also be considered an optimization. I would consider it optimization. But basically it is a "not zero" test => which is correct to. zero is one of the two allowed values. I think so that the optimisation bit is defensible too. The question is if that optimisation was intended So it might be worth a bugreport and some tests on other architectures. Is there a case were it does not work as documented? Btw, I was to fast (but still stand by, its ok, and even looks indented) It is not a test for zero. Well, the "orw" does set the zero flag (if di is zero) Then the "setneb"  NE  => Not Equal => zero flag not set. But the "setneb" is why I say its indented. Its a conditional set, it avoids a branch. So the CPU can much faster execute it (no branch prediction needed) ---------------------------------------------------------------------- 440bx · 2025-01-28 20:46 Quote from: Martin_fr on January 28, 2025, 06:21:36 pm"One is the only one that yields true" is a half truth. Table 3.4 Boolean types clearly indicates that the value 1 is the only value considered TRUE for Boolean, Boolean16, Boolean32 and Boolean64.    When other values are considered TRUE, the table indicates "any nonzero value" and that is not what it states for those types.  IOW, according to the documentation, if ord(boolean_var) <> 1 then boolean_var is supposedly FALSE.  Supposedly, that's the difference between the BooleanXX and the xxxBool type family. OTH, the compiler doesn't see it that way depending on how the variable is being used.  On a different note, the statement "ord(b8) := 4" can be subsituted by "b8 := boolean(4)" and there is no change whatsoever in the results and code generated.  IOW, the statements are functionally and semantically equivalent.   The same applies to b16. ---------------------------------------------------------------------- Martin_fr · 2025-01-28 21:08 Quote from: 440bx on January 28, 2025, 09:46:23 pmTable 3.4 Boolean types clearly indicates that the value 1 is the only value considered TRUE for Boolean, Boolean16, Boolean32 and Boolean64.    When other values are considered TRUE, the table indicates "any nonzero value" and that is not what it states for those types.  IOW, according to the documentation, if ord(boolean_var) <> 1 then boolean_var is supposedly FALSE.  Supposedly, that's the difference between the BooleanXX and the xxxBool type family. Then at best it is an issue with the documentation. - Which does not contain explicitly the statement, that the only allowed ordinal values are 0 and 1. - Or in other words that "0 is the only value that yields false" - Mind that also nowhere in that documentation it says that "every value <> 1 yields false". - And it certainly does not state that every ordinal (or every ordinal fitting into a given size) is a valid input. It does say Quotewith its two predefined possible values and Quote As an integer, the values for True and False are 1 and 0. (if a boolean value is interpreted as an integer then....) The only ordinal value that the documentation actually states to be false is 0. All other value are not specified in the documentation (for Boolean / they are for ByteBool). And that makes sense. As far as the documentation should be concerned, they do not exist. They are not defined. it also does not state what happens for MyByteBool = 256  MyByteBool = 257 Those are range check errors, but if not caught, they may yield one of the 2 boolean values. Especially, if unlucky, and by random chance the 256 (even it is not zero) may yield False in a ByteBool. Yet it may not in all cases.... (don't know) But feel free to ask for the documentation to be more explicit. ---------------------------------------------------------------------- 440bx · 2025-01-28 21:22 Quote from: tetrastes on January 28, 2025, 10:03:11 amQuote from: Thaddy on January 28, 2025, 09:04:22 ambut the issue is simply that he seems to think Ord() is a cast, whereas it is of course a function. Then why Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ord(b8)  := 4;is compiled at all? You cannot do that with a function: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function BoolToInt(b: boolean): longint;begin    Result := ord(b);end;. . . BoolToInt(b8) := 4; is not compiled with "Error: Argument cannot be assigned to". @Zoran, the reason for the error is because a function's result cannot be set outside the function which is what "BoolToInt(b8) := 4;" tries to do. That shows that the compiler doesn't see "ord" as a function but as a cast, otherwise "ord(b8) := 4;" would not be acceptable.  The advantage of using "ord" as a cast is that "ord" adapts to the size of its argument whereas a specific type does not.  IOW, trying "integer(b8) := 4;" fails because b8 is too small to be cast to integer. For a cast to work it would need to be cast to "Shortint" or "Byte".  Ord spares the programmer from having to take argument size into consideration.  That's another reason why "ord" shouldn't be considered a function, a function's result, unlike ord, _cannot_vary in size. HTH. ---------------------------------------------------------------------- 440bx · 2025-01-28 21:50 @Martin, The _strict_, _mathematical_ and _correct_ definition of a boolean is an object (not in the sense of OOP) that can only have two (2) values: 0 and 1.  Nothing else is allowed.  By convention, 1 is usually considered to be TRUE and 0 usually considered FALSE. Problems sometimes arise because of the fact that booleans are usually represented with 8, 16, 32 or 64 bits which is a lot more than the 1 bit required for 0 and 1. Strictly speaking in the byte, word, dword and qword used to represent a boolean, only 1 bit is significant, the rest of the bits are uninvited guests the compiler has no business accounting for under _any_ circumstances and the code it generates _must_ account for that.    Code that in any way allows those extra bits to alter the truth value is simply incorrect. The documentation is correct, for those types, only the value 1 is TRUE and, the documentation implies by its stating "with its two predefined values True and False" that, only the value 0 is FALSE.  In some situations, the code generated by the compiler, FPC in this case, fails to enforce that condition.  That is a bug and it is made evident when the inconsistent treatment yields different truth values assigned to _bits_ when going from a larger types to a single bit type. Lastly, it is important to note that ByteBool, WordBool, LongBool and QWordBool are _not_ booleans, they are a C-ism where 0 is FALSE and any other value is TRUE.  That is NOT what a boolean is, consequently the rules that apply to them are different. ---------------------------------------------------------------------- Martin_fr · 2025-01-28 22:00 Well, we are talking about Pascal, not about Maths. But, yes, the 1 or 0 rule remains (for the non "ByteBool"). And yes, the other bits are an error (in the sense of "not allowed"). And I have been saying that. If they are set, then the behaviour is undefined => as behaviour for "not allowed" values is throughout fpc generated code. Code simply does not check for that, it simply makes assumptions, and that is fine as valid code would never break them. And, yeah different topic, don't make assumptions.... ---------------------------------------------------------------------- TRon · 2025-01-28 22:02 Quote from: Martin_fr on January 28, 2025, 11:00:04 pmBut, yes, the 1 or 0 rule remains (for the non "ByteBool"). Are you sure about that ? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   writeln('boolean(0) = ', boolean(0));  writeln('boolean(1) = ', boolean(1));  writeln('boolean(2) = ', boolean(2));  writeln('boolean(3) = ', boolean(3));  writeln('boolean(128) = ', boolean(128)); ---------------------------------------------------------------------- 440bx · 2025-01-28 22:10 Quote from: Martin_fr on January 28, 2025, 11:00:04 pmWell, we are talking about Pascal, not about Maths. Pascal is implementing a Mathematical concept, therefore it has to be true to the mathematical definition.   IOW, Pascal cannot give itself the luxury of redefining mathematical concepts. Quote from: Martin_fr on January 28, 2025, 11:00:04 pmAnd yes, the other bits are an error (in the sense of "not allowed"). And I have been saying that. If they are set, then the behaviour is undefined => as behaviour for "not allowed" values is throughout fpc generated code. Code simply does not check for that, it simply makes assumptions, and that is fine as valid code would never break them. No.  The behavior is not undefined.  It is _defined_ that only 1 bit is significant and that is from the definition of boolean (only 2 values, 0 and 1).  Therefore, whenever FPC is allowing other bits that are neither here nor there to alter the meaning of the 1 bit that matters, that's a well defined bug. ---------------------------------------------------------------------- Martin_fr · 2025-01-28 22:16 Quote from: TRon on January 28, 2025, 11:02:41 pmQuote from: Martin_fr on January 28, 2025, 11:00:04 pmBut, yes, the 1 or 0 rule remains (for the non "ByteBool"). Are you sure about that ? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   writeln('boolean(0) = ', boolean(0));  writeln('boolean(1) = ', boolean(1));  writeln('boolean(2) = ', boolean(2));  writeln('boolean(3) = ', boolean(3));  writeln('boolean(128) = ', boolean(128));  Yes, (but ask someone from the fpc team, if you don't believe me => they defined the rules what the compiler should see in the language). Mind that "only 1 or 2" means the rest has no defined behaviour. => It may still give the "expected" (as expected by you) result by chance. But then you update the compiler, change a setting, change seemingly unrelated code, and it may not give the "expected" result. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program Project1;var a,b: boolean;begin  a := Boolean(2);  b := Boolean(3);  if a=b then writeln('!');  readln;end.  For me prints nothing. But its not defined. Using ByteBool, it will print. ---------------------------------------------------------------------- TRon · 2025-01-28 22:25 Quote from: Martin_fr on January 28, 2025, 11:16:42 pmYes, (but ask someone from the fpc team, if you don't believe me => they defined the rules what the compiler should see in the language). Mind that "only 1 or 2" means the rest has no defined behaviour. => It may still give the "expected" (as expected by you) result by chance. But then you update the compiler, change a setting, change seemingly unrelated code, and it may not give the "expected" result. That might very well be the case but the documentation is clear. 0 or 1, nothing else. The example-code I used definitely does not adhere to the documentation. Even stronger the results from that code seem to suggest 0 (and only 0) is false and every bool not zero is treated as true (size of the boolean does not matter btw). Even if the compiler does something different to it as an expression rather than f.e. assigning it to an actual boolean typed variable then there certainly is something off there. Perhaps someone of the FPC team (w/c)ould indeed comment on that. ---------------------------------------------------------------------- Martin_fr · 2025-01-28 22:26 Quote from: 440bx on January 28, 2025, 11:10:52 pmQuote from: Martin_fr on January 28, 2025, 11:00:04 pmWell, we are talking about Pascal, not about Maths. Pascal is implementing a Mathematical concept, therefore it has to be true to the mathematical definition.   IOW, Pascal cannot give itself the luxury of redefining mathematical concepts. Quote from: Martin_fr on January 28, 2025, 11:00:04 pmAnd yes, the other bits are an error (in the sense of "not allowed"). And I have been saying that. If they are set, then the behaviour is undefined => as behaviour for "not allowed" values is throughout fpc generated code. Code simply does not check for that, it simply makes assumptions, and that is fine as valid code would never break them. No.  The behavior is not undefined.  It is _defined_ that only 1 bit is significant and that is from the definition of boolean (only 2 values, 0 and 1).  Therefore, whenever FPC is allowing other bits that are neither here nor there to alter the meaning of the 1 bit that matters, that's a well defined bug. Feel free to take that up with the FPC team. If they document it, to explicitly state something different from what I said, then please let me know, so I can update my knowledge. For all else, and until then, since my statements are based on what I have learned about Pascal from the FPC team (by various direct and indirect means). It has worked well till here. I will continue to base my work on that knowledge, because at this time I believe I have better chances at success by following the FPC team on this particular topic, than following your definitions. Especially when they match exactly what the compiler does. (As confirmation of the info gained from trusted sources / not otherwise relevant) ---------------------------------------------------------------------- TRon · 2025-01-28 22:44 @Martin_fr btw and fwiw in your example (thank you for that because it is a perfect illustration for the confusion in case there is any) the reason that those two booleans are not the same is because their ordinal value differ, and not their boolean value. So it seems that the compiler compares them (internally) as being integers. I consider that unexpected (and afaik undocumented) edit: /me hides into black hole Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure HowToCompareTheTruth;var  a,b: boolean;begin  a := Boolean(2);  b := Boolean(3);   if a=b then writeln('!');   writeln('a = ', a);  writeln('b = ', b);   writeln('ord(a) = ', ord(a));  writeln('ord(b) = ', ord(b));   if (Boolean(a) = Boolean(b)) then writeln('*');   writeln('boolean(a) = ', boolean(a));  writeln('boolean(b) = ', boolean(b));   writeln('ord(boolean(a)) = ', ord(boolean(a)));  writeln('ord(boolean(b)) = ', ord(boolean(b)));end;  Above which btw does work as expected for boolean16. ---------------------------------------------------------------------- 440bx · 2025-01-28 23:06 Quote from: Martin_fr on January 28, 2025, 11:26:39 pmWell, we are talking about Pascal, not about Maths. ... If they document it, to explicitly state something different from what I said, then please let me know, so I can update my knowledge. You, yourself said that for the BooleanXX types there are only two values allowed, 0 and 1 and, you pointed out that fact by quoting the "with its two predefined values... etc". I believe we both agree that a true boolean (not the C bool stuff) can only have values 0 and 1. FPC is not adhering to the spec which is: boolean values are either 0 or 1.  It is failing to adhere to that when it generates an "or al, al" or "or ax, ax" to determine the truth value of a boolean.  Such tests can only be used for types that are true for any nonzero value, not for a real boolean. The same thing when it compares against 0 to determine truth value.  When a boolean is represented by more than 1 bit then not zero is NOT equal to TRUE because it confers meaning to bits that, by definition, do not have any. The one thing that I am in full agreement with you is that one of the FPC developers should shed some light on the issue. ---------------------------------------------------------------------- ASerge · 2025-01-28 23:32 Quote from: 440bx on January 28, 2025, 07:10:37 amComments welcome. Assignment Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     Ord(b8) := 4; // true    Ord(b16) := 8;  // truenot correct for Boolean type. Change variable type as Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     b8: ByteBool = False;    b16: WordBool = False;to make the result correct. ---------------------------------------------------------------------- 440bx · 2025-01-28 23:39 Quote from: ASerge on January 29, 2025, 12:32:43 amQuote from: 440bx on January 28, 2025, 07:10:37 amComments welcome. Assignment Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     Ord(b8) := 4; // true    Ord(b16) := 8;  // truenot correct for Boolean type. That's true, a boolean should not accommodate a value greater than 1 but... because booleans are usually implemented using types larger than 1 bit, the compiler "tolerates" assignments like that because underlying the boolean type is an integer type (see the FPC documentation.)  However, when the boolean variable is tested for its truth value, the compiler MUST test a single bit regardless of the size of the underlying integer type.  Doing otherwise yields incorrect results. The compiler could choose to disallow casts such as "ord(b8) := 4;" but, that is not sufficient to ensure the proper treatment of boolean types. ---------------------------------------------------------------------- TRon · 2025-01-28 23:47 Quote from: 440bx on January 29, 2025, 12:39:39 amThe compiler could choose to disallow casts such as "ord(b8) := 4;" but, that is not sufficient to ensure the proper treatment of boolean types. And does not hold up for the boolean16 type. ---------------------------------------------------------------------- 440bx · 2025-01-28 23:50 Quote from: TRon on January 29, 2025, 12:47:21 amAnd does not hold up for the boolean16 type. I don't think I am getting what you mean.  Can you elaborate please ?  Thank you. ---------------------------------------------------------------------- TRon · 2025-01-28 23:57 Quote from: 440bx on January 29, 2025, 12:50:40 amI don't think I am getting what you mean.  Can you elaborate please ?  Thank you. According to documentation: QuoteIn addition to the simple Boolean type, the additional Boolean16, Boolean32 and Boolean64 types exist. These are in fact integer types, which are assignment-compatible with the simple boolean type. As an integer, the values for True and False are 1 and 0. This can be used to interface with C code that defines a boolean of this size with values 0 and 1. So, while the statement you made might be true for the boolean type (as details other than written are further undocumented) this allows for the interpretation that you can assign an integer value to a boolean16 or boolean32 type.  If you look at the modified example from martin that I posted, that fails miserably for boolean (unable to compare the booleans against each other) but can perhaps be described as being undefined behaviour. Doing the same for boolean16 does work as intended and according to the bolded part also should (imho). Nonetheless, 0 is zero and 1 is one *period* ---------------------------------------------------------------------- 440bx · 2025-01-29 00:11 Quote from: TRon on January 29, 2025, 12:57:15 am this allows for the interpretation that you can assign an integer value to a boolean16 or boolean32 type. I see your point now, thank you for clarifying.  However, the sentence that follows reinforces that even for those types, the values for TRUE and FALSE are 1 and 0 (respectively).  Therefore, IMO, they should still be treated as harboring a single bit thus unable to accommodate values greater than 1. ---------------------------------------------------------------------- TRon · 2025-01-29 00:28 Quote from: 440bx on January 29, 2025, 01:11:07 amI see your point now, thank you for clarifying.  No problem. fwiw the fact that in your original example the code does the casts the other way around should imho not matter. QuoteHowever, the sentence that follows reinforces that even for those types, the values for TRUE and FALSE are 1 and 0 (respectively).  Therefore, IMO, they should still be treated as harboring a single bit thus unable to accommodate values greater than 1. Although in general I agree with that interpretation I am however a bit more hesitant because the following: QuoteThe only difference with the Boolean16/32/64 types So while that reinforces that it is possible for bool16/32/64 to be assigned an integer the documentation cleverly leaves out the boolean type  No matter what: ord(true) = 1 as per documentation and that clearly isn't the case (whatever booleanXX type) . That is why I ended my previous reply last sentence with period because something is off. Wouldn't surprise me if that would be caused by Delphi sickness ---------------------------------------------------------------------- Fred vS · 2025-01-29 01:11 Quote from: marcov on January 28, 2025, 07:58:43 pmQuote from: Fred vS on January 28, 2025, 06:57:34 pmSorry to be a troublemaker but why use the problematic boolean? It's easier to use byte and if result < 1 it's false and if result > 0 it's true. Unless you accidentally use a signed expression. So use <>0. Hum, the trick mentioned: It's easier to use byte So using byte(-25) will give 231 as result who is, imho, > 0. The same for every value, even > 256 or < 0, the value is always unsigned. The same if you use a boolean: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i varabool : boolean = false; ...writeln(byte(abool)); // will give 0 as result and 1 if abool is true. Or, of course, once again, I miss something. ---------------------------------------------------------------------- ASerge · 2025-01-29 01:42 Quote from: 440bx on January 29, 2025, 12:39:39 am..., the compiler "tolerates" assignments like that because underlying the boolean type is an integer type But this is explicit typecast, so programmer take responsibility for what follows. In this case, the used the wrong type, so he ran into a problem. ---------------------------------------------------------------------- 440bx · 2025-01-29 02:52 Quote from: ASerge on January 29, 2025, 02:42:09 amQuote from: 440bx on January 29, 2025, 12:39:39 am..., the compiler "tolerates" assignments like that because underlying the boolean type is an integer type But this is explicit typecast, so programmer take responsibility for what follows. In this case, the used the wrong type, so he ran into a problem. That is a reasonable argument but... the compiler isn't allowed to do things wrong because the programmer did it wrong.  IOW, no matter what the programmer does, the compiler is still expected to do what is correct. The compiler's acceptance of invalid typecasts doesn't absolve it from producing code that enforces the specs that define a boolean, which is, 0 = false and 1 = true.  Additionally, the compiler should reject that cast because it is invalid.  The compiler should treat a true/genuine boolean type as being a single bit type and neither 4 nor 8 fit in a single bit, therefore those casts are invalid and the compiler should reject them the same way it rejects a cast such as "integer(b8) := 4;" I think there is a good argument to be made that accepting those casts is itself a bug (but, I know the developers wouldn't go for it because it would be too inconvenient.) ---------------------------------------------------------------------- TRon · 2025-01-29 03:41 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  a : boolean = false;  i : integer;begin  for i := 1 to 10 do  begin    writeln('a(',i,') ord(a) = ', ord(a), ' a = ', a);    inc(a);  end;end.  Programmer's mistake #42 ---------------------------------------------------------------------- 440bx · 2025-01-29 08:39 I thought it would be appropriate to mention that the statement: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ord(b8) := 4;Is not acceptable to Delphi.  Delphi does consider "ord" to be a function and as such cannot be assigned a value. FPC "sees" it a different way (likely as just a cast) ---------------------------------------------------------------------- marcov · 2025-01-29 09:04 Bugs that make a case about giving undefined values of booleans meaning have been closed with "won't fix" for decades, and IMHO rightfully so because it inhibits optimisations. I don't think that this way of reasoning will amount to much. ---------------------------------------------------------------------- 440bx · 2025-01-29 10:20 Quote from: marcov on January 29, 2025, 10:04:19 amBugs that make a case about giving undefined values of booleans meaning have been closed with "won't fix" for decades, and IMHO rightfully so because it inhibits optimisations. I don't think that this way of reasoning will amount to much. The compiler should not accept those values, it knows they are invalid.  If, for whatever reason, the compiler allows them then it is its responsibility to ensure they do not get in the way of ensuring logical correctness.  Given that Pascal is supposed to be a strongly typed language those definitions should be unacceptable, just as "integer(b8) := 4;" is unacceptable. A boolean is a single bit.  The only reason it is represented with a byte, word, dword or qword is to allow addressability since no CPU (at least that I know of) allows addressing single bits.  Addressability does not change the fact that the storage size of a boolean is 1 bit. Lastly, the compiler's first and foremost responsibility is to produce correct code. speed, optimizations or any other concerns are secondary to that one.  IOW, optimizations and speed concerns do not justify producing incorrect code. ---------------------------------------------------------------------- marcov · 2025-01-29 10:33 Quote from: 440bx on January 29, 2025, 11:20:14 amLastly, the compiler's first and foremost responsibility is to produce correct code. speed, optimizations or any other concerns are secondary to that one.  IOW, optimizations and speed concerns do not justify producing incorrect code. Non 0/1 values are considered undefined, and any operation on such variable gives an undefined result. The reason to leave it that way is optimisation.   Trying to close those gaps to assign values to booleans only complicates the RTL and people writing streaming code for booleans, for at best hypothetical gains. ---------------------------------------------------------------------- 440bx · 2025-01-29 10:58 Quote from: marcov on January 29, 2025, 11:33:40 amQuote from: 440bx on January 29, 2025, 11:20:14 amLastly, the compiler's first and foremost responsibility is to produce correct code. speed, optimizations or any other concerns are secondary to that one.  IOW, optimizations and speed concerns do not justify producing incorrect code. Non 0/1 values are considered undefined, and any operation on such variable gives an undefined result. And how do you justify the compiler accepting "ord(b8) := 4;" while rejecting "integer(b8) := 4;", it is rather easy to reject the first one too.  Why should the compiler allow "undefined" values ?  How can that be justified ?  (code wise it's rather simple to disallow those undefined boolean values. However, that is not sufficient, the code the compiler generates needs to be changed because it is incorrect even when the compiler prevents undefined values.) Quote from: marcov on January 29, 2025, 11:33:40 amThe reason to leave it that way is optimisation.   Trying to close those gaps to assign values to booleans only complicates the RTL and people writing streaming code for booleans, for at best hypothetical gains. Did optimization (or speed) become more important than correctness ?   if correctness still rules the day then a change in FPC is necessary.  Bugs are inconvenient and fixing them is usually inconvenient too but, that isn't normally a reason given to leave them uncorrected. Also, The documentation states: QuoteFree Pascal supports the Boolean type, with its two predefined possible values True and False. These are the only two values that can be assigned to a Boolean type. ... In addition to the simple Boolean type, the additional Boolean16, Boolean32 and Boolean64 types exist. These are in fact integer types, which are assignment- compatible with the simple boolean type. As an integer, the values for True and False are 1 and 0. Emphasis mine.  The typecasts show that TRUE and FALSE are most definitely NOT the only two values that can be assigned to a Boolean type. Now the problem is, the documentation is correct but the compiler is not operating as the spec/documentation requires. Possible fixes: a. "amend" the documentation to state the compiler allows values other than TRUE and FALSE for a boolean. or b. correct the compiler so it treats booleans correctly. if (a) then it would be nice to include a warning in the documentation that unpredictable results should be expected in that case.  It would also be nice if the compiler emitted a warning stating as much too. if (b) then the compiler would operate as documented which is a nice plus (correctness: 1, optimizations: do it right first, then do it faster while keeping it right) ---------------------------------------------------------------------- marcov · 2025-01-29 11:09 Quote from: 440bx on January 29, 2025, 11:58:44 amAnd how do you justify the compiler accepting "ord(b8) := 4;" while rejecting "integer(b8) := 4;", it is rather easy to reject the first one too.  That is because the lvalue size doesn't match for a typecast, and you can't assign to a conversion. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var b : boolean; begin  b:=boolean(20);  byte(b):=4;  // match size  writeln(ord(b));end.  Anyway I don't, I reacted to the outcome further along, the evaluation of a b16 with <>0 rather than =1. The ord() thing has nothing to do with optimization. QuoteWhy should the compiler allow "undefined" values ?  Because if they were defined, additional code of would have to be generated to address scenarios of low real value. And I already hinted on why access to those bits is allowed with typecasts, for variant and streaming code. ---------------------------------------------------------------------- 440bx · 2025-01-29 11:18 Quote from: marcov on January 29, 2025, 12:09:55 pmBecause if they were defined, additional code of would have to be generated to address scenarios of low real value. And I already hinted on why access to those bits is allowed with typecasts, for variant and streaming code. No.  The changes in the code would not have a significant impact on performance.  It may not even have any at all. For instance, instead of having "cmp [rbp - 08], 0" it would have "and [rbp - 08], 1" to determine the truth value.  The performance difference is negligible and, that would be the case in other instances as well where the compiler (incorrectly) generates "or ax, ax" to determine if ax is nonzero instead of using an instruction to determine the value of the LSB. The difference in the generated code is minimal and, disallowing invalid values is code wise trivial. ---------------------------------------------------------------------- marcov · 2025-01-29 11:24 - Not everything is about x86(_64) - on risc systems loading literals into a register requires extra instructions. - Even on x86 shorter code often avoids decoding bottlenecks. And again: the alternative scenarios to have no value to begin with. It only puts unnecessary constraints on the code to save people that recklessly filled booleans with casts. ---------------------------------------------------------------------- 440bx · 2025-01-29 11:38 Quote from: marcov on January 29, 2025, 12:24:17 pm save people that recklessly filled booleans with casts. Isn't Pascal supposed to catch and prevent instances of "reckless" programming ?  It does when casting b8 to an integer and casting the numeral 4 to a boolean is just as incorrect (4 is too large to fit in a bit, which is what a boolean is.) How about the documentation ?... should the documentation still state that only 0 and 1 are allowed (which is not the case) ?  CPU architecture and performance should never be allowed to get in the way of correctness (and fortunately they _usually_ aren't.) ---------------------------------------------------------------------- WooBean · 2025-01-29 12:09 440bx "Isn't Pascal supposed to catch and prevent instances of "reckless" programming ?" Do not destroy the last hole to survive at keeping alive old binary protocols when some extra bits are needed now and we cannot modify protocol for some existing participants. No action needed. ---------------------------------------------------------------------- Martin_fr · 2025-01-29 12:20 Quote from: 440bx on January 29, 2025, 11:58:44 amDid optimization (or speed) become more important than correctness ?  Correctness based on what definition? I know you want it to be "mathematical correct" (i.e. following the definition the selected terms have in maths). But, that is just what you want. That is not what may be defined as correct in terms of the Language, or the specific implementation of the language by the given compiler. (Never mind if you find that acceptable) ---------------------------------------------------------------------- marcov · 2025-01-29 12:22 Quote from: 440bx on January 29, 2025, 12:38:32 pmQuote from: marcov on January 29, 2025, 12:24:17 pm save people that recklessly filled booleans with casts. Isn't Pascal supposed to catch and prevent instances of "reckless" programming ? Yes, to avoid mistakes. But typecasts are the overrides for that safety system, and as such not subject to it. ---------------------------------------------------------------------- 440bx · 2025-01-29 12:33 Quote from: Martin_fr on January 29, 2025, 01:20:16 pmThat is not what may be defined as correct in terms of the Language, or the specific implementation of the language by the given compiler. (Never mind if you find that acceptable) No, correct is not  a relative term.  There are a number of incorrect things, among them: 1. the documentation states that TRUE and FALSE are the only values that can be assigned to the boolean type, that's INCORRECT (and it has nothing to do with the fact that I find it unacceptable, it's INCORRECT whether I or anyone else finds it acceptable or unacceptable.) 2. assigning a value greater than 1 to a boolean is INCORRECT.  A boolean is an object that has only two states, therefore it cannot represent a fifth state (the numeral 4 - which is fifth from zero included.) 3. if the compiler considers a value TRUE when it is in an 8/16/32/64 bit structure then that TRUE bit must also be TRUE when represented as a single bit (a bitpacked array element.)  IOW, it cannot suffer a Kafkan mutation when stored in a single bit. None of the above, have anything to do with what I personally consider correct or otherwise.  As you pointed out, it's either math or logic. Quote from: marcov on January 29, 2025, 01:22:55 pmQuote from: 440bx on January 29, 2025, 12:38:32 pmQuote from: marcov on January 29, 2025, 12:24:17 pm save people that recklessly filled booleans with casts. Isn't Pascal supposed to catch and prevent instances of "reckless" programming ? Yes, to avoid mistakes. But typecasts are the overrides for that safety system, and as such not subject to it. The compiler rejects invalid typecasts.  It should reject those since they are as invalid as "integer(b8) := 4;"  Accepting those typecast is, by itself, a bug (which has additional undesirable consequences.) ---------------------------------------------------------------------- Martin_fr · 2025-01-29 12:47 Quote from: 440bx on January 29, 2025, 01:33:06 pmQuote from: Martin_fr on January 29, 2025, 01:20:16 pmThat is not what may be defined as correct in terms of the Language, or the specific implementation of the language by the given compiler. (Never mind if you find that acceptable) No, correct is not  a relative term.  True. Its absolutely defined by the documentation (the FPC Pascal documentation). Or rather the "would be", if it would be error free. I am not arguing if the doc can be improved. It is fine for me, but maybe could be better. I don't agree with all of your issues with the doc, but that is a different topic. I was arguing that the implemented behaviour (the one we discussed: or / setneb) is correct. - I believe the documentation is indented to specify that to be expected. (again, not arguing if it is best written to convey this) - I believe the documentation has the right to define this. (I.e. if someone creates a Pascal dialect, and that is what fpc is, then they define the rules) ---------------------------------------------------------------------- ASerge · 2025-01-29 20:56 Quote from: 440bx on January 29, 2025, 01:33:06 pmThe compiler rejects invalid typecasts.  It should reject those since they are as invalid as "integer(b8) := 4;" Not! Typecast is a useful tool. Each time the sizes match, the compiler must allow typecast. If someone intentionally misuses it, that's not a reason to reject it. ---------------------------------------------------------------------- 440bx · 2025-01-29 21:26 Quote from: ASerge on January 29, 2025, 09:56:34 pmQuote from: 440bx on January 29, 2025, 01:33:06 pmThe compiler rejects invalid typecasts.  It should reject those since they are as invalid as "integer(b8) := 4;" Not! Typecast is a useful tool. Each time the sizes match, the compiler must allow typecast. If someone intentionally misuses it, that's not a reason to reject it. The size of a boolean is NOT 8 nor 16 nor 32 nor 64 bits, it is 1 bit, again: 1 _bit_. Therefore any attempt of storing a value greater than 1 in 1 bit is invalid.  The cast is invalid.  "byte(b8) := 4;" is as invalid as "integer(b8) := 4;", the reason: a boolean is 1 and only 1 bit, not 8, not 16, not 32, not 64.  Therefore in both cases the cast is invalid due to a size mismatch. The reason booleans are stored in integers is because of addressability but that does not change the fact that a boolean is a single bit.  The cast is invalid and the compiler _should_ not allow it.  Additionally, the documentation says that only zero and one are valid for boolean. Bug 1: the compiler allowed an invalid typecast. Bug 2: after making a mess as a result of Bug 1, it made a another mess when assigning false to a bit that was being assigned a value it erroneously claimed was true. What a mess! (but it's an optimized mess... it's fast... that's really important) Out of curiosity: should the documentation be corrected to let programmers know that values other than zero and one can be assigned to a boolean ?   if you consider that cast valid then you must answer "yes" to that question.  OTH, if the cast is invalid then the documentation is correct as it currently stands (which it is) and it is the compiler that should comply with the documentation (casting is not an excuse... can't cast a string to a boolean... can't cast the Saturn V rocket into a Toyota Yaris... can't cast the numeral 4 into a single bit.) The real problem is: Delphi accepts "b8 := boolean(4);" which is obviously incorrect but, FPC will use that as the reason to allow it and also allow "ord(b8) := 4;" Another "writable constant"... that's what happens when a language is abandoned, i.e. there isn't a group of qualified language designers creating and updating standards for it.  oh well... the bug is alive, long live the bug! ---------------------------------------------------------------------- Fred vS · 2025-01-29 22:52 Quote from: 440bx on January 29, 2025, 10:26:50 pmBug 1: the compiler allowed an invalid typecast. But how else to do it, the smallest type size being byte/char (8 bits)? Pascal does not provide a native one-bit type (which should be used for booleans). ---------------------------------------------------------------------- Martin_fr · 2025-01-29 23:15 Quote from: Fred vS on January 29, 2025, 11:52:57 pmBut how else to do it, the smallest type size being byte/char (8 bits)? Pascal does not provide a native one-bit type (which should be used for booleans). He tries to fit the definition of boolean in FreePascal into (over? around?) the Mathematical concept. Of course that wont work, because Math does (afaik) not describe how to store a boolean value in different media. Just like Unicode needs the Unicode transfer encoding, a computer program needs defined storage for a boolean. Of course one could (and we can argue about "one should") chose the smallest available container. But this isn't about maths at that point. So if desired technically it is possible to choose storage/encoding in bigger containers. In other word, choosing other storage than a single bit is possible. (And one might think of it as good or bad, but that does not change that it can be done). So Boolean32 chooses to store in a 4byte container. And all 32 bits are part of the value (yes total overkill, don't need them, but still doing it) It chooses to encode False = 00000000000000000000000000000000 True = 00000000000000000000000000000001 Any other value is not valid. If we change the storage we have to change the encoding. In A boolean8 it will be 00000000 and 00000001. ----------------- And then yes, one could argue the compiler should check the full value each time it accesses such media. That might be an idea for a "bool range check" option. Otherwise the code is based on that it only needs to work if values are within the valid encodings. And with that given, we can reduce any code to a check that can distinguish the valid encoded values, and not care about anything else. Mind this "only deal with valid" is true for many other values too. Enums have the same rules. Other values may also have valid vs invalid. The hidden pointer in ansistring must be nil, or point to accessible mem with a specific data layout.... But there are no plausibility checks when accessing it. ---------------------------------------------------------------------- 440bx · 2025-01-29 23:34 Quote from: Fred vS on January 29, 2025, 11:52:57 pmQuote from: 440bx on January 29, 2025, 10:26:50 pmBug 1: the compiler allowed an invalid typecast. But how else to do it, the smallest type size being byte/char (8 bits)? Pascal does not provide a native one-bit type (which should be used for booleans). True, the smallest _addressable_ size is byte.   In the case of boolean, the type size and the storage size can differ (they don't in the case of a bitpacked array of boolean).   When dealing with booleans the compiler should use the type size _not_ the storage size.  The storage size affects addressability but never affects the fact that a boolean is a single bit.  The compiler should make that distinction. All that said, since Delphi accepts the invalid typecast, it is rather unlikely that this bug will be corrected (because Delphi compatibility is more "important" than correctness.) It's also interesting that the majority of posters, including myself, consider the cast to be invalid but, there is no mention that the compiler should not allow the invalid cast.  IOW, the compiler accepts something it should not accept but, if and when a programmer uses that invalid construction, it's not the compiler's fault, it's the programmer's.  ain't that great ?  Talk about the guilty party pointing the finger at someone else and saying "he did it !" @Martin, You're right that math does not say how a boolean should be stored BUT, it does say that it has only two states and, in a computer that's a bit.  No way around it.  boolean = 2 states = 1 bit. It doesn't matter how it is stored, the number of states is the same: 2 and only 2. Therefore, by definition, a boolean occupies a single bit. Due to addressability reasons, that single bit is usually part of a byte or word or dword or qword but, no matter the container, it is and will always be a single bit.  The bottom line is simple: no matter how many bits there are in the container, only 1 bit is significant, the rest are not and they are not part of the type therefore the compiler should NOT allow their being manipulated because they are not used to represent the type's value. It is incorrect and meaningless for the compiler to allow the non- significant bits to be manipulated and, if for convenience or compatibility with Delphi, it decides to allow it then those bits should always be ignored because they are not part of the data type, just "tolerated" guests in the container to enable simple addressability. ---------------------------------------------------------------------- Martin_fr · 2025-01-29 23:42 And what if it was stored with a "checksum" => choosing multiple bits that must have a pattern, so that if any one bit rotted then it would be detected? I guess you would not say that hardware with error correction bits is unable to store boolean values? I know, we don't use the encoded value as a such a pattern. Fpc doesn't check the validity. But that isn't the point of my above statement. I am simple saying there are reasons that could warrant storage with multiple bits - all equally significant. So it is not some given that it must be a single bit. And if it is not a given, then it may be a multi bit encoding - even for no good reason at all. (or at least, no reason you seem to see as good) ---------------------------------------------------------------------- 440bx · 2025-01-30 00:27 Quote from: Martin_fr on January 30, 2025, 12:42:33 amAnd what if it was stored with a "checksum" => choosing multiple bits that must have a pattern, so that if any one bit rotted then it would be detected? Obviously a checksum applies only to a sequence of bits.  Each bit in that sequence is still one of two possible states, no way around that and the checksum is a separate entity.  Parity and ECC implement detection and limited recovery in the case of ECC but, the bits are still just bits, 1s and 0s, checksum, ecc or any other checking mechanism. IOW, a checksum changes absolutely nothing.  Bits are still two states and a boolean is still a single bit.  It doesn't matter if there is one boolean or 1 million of them, they are all 1 bit.  The presence of additional bits to ensure correctness changes nothing. Do you consider the documentation statement:QuoteFree Pascal supports the Boolean type, with its two predefined possible values True and False. These are the only two values that can be assigned to a Boolean type.to be true or false ? It sounds boolean(4) to me but, I strongly believe the compiler should fully enforce it without exception. ---------------------------------------------------------------------- Fred vS · 2025-01-30 00:29 Quote from: Martin_fr on January 30, 2025, 12:42:33 amAnd what if it was stored with a "checksum" => choosing multiple bits that must have a pattern, so that if any one bit rotted then it would be detected? Ha, ok, it is (maybe) why it exists type boolean32.  But how would you do to create a "checksum" (very nice idea to check if the value has all the right). With this example: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i varabol : boolean32;...beginabol := boolean32(123456789);  // the integer > 0 that will set abol as "true"writeln(word(abol)); the result is 52501, so what is the relation with 123456789? (It is more for the game, not sure it would be useful for something) ---------------------------------------------------------------------- Martin_fr · 2025-01-30 00:40 Quote from: Fred vS on January 30, 2025, 01:29:36 amHa, ok, it is (maybe) why it exists type boolean32.  But how would you do to create a "checksum" (very nice idea to check if the value has all the right). "chekcsum" does not need to be computed. It could be a specific pattern. Bitrot would be unlikely to translate it into exactly one of the 2 valid patterns. And no, its not the reason for boolean32 => Most likely that is - easy of implementation - optimization Both of which, I guess, would be "not a reason" for 440bx. But they may have been for the decision makers. If so, the rest of us has to accept it. We already clarified that the before mention boolean in maths has no say on the storage form => therefore it also does not dictate a minimum storage or single bit. Hence we can store it in a multi byte storage, and we can demand that all bits are set according to the encoding, and that values not matching the encoding are undefined. (We know it can be done. It has already be done) ---------------------------------------------------------------------- Fred vS · 2025-01-30 00:59 Thanks Martin for the always clear answer. To stupid me: QuoteWith this example: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i varabol : boolean32;...beginabol := boolean32(123456789);  // the integer <> 0 that will set abol as "true"writeln(word(abol)); the result is 52501, so what is the relation with 123456789? It is because you used word that is 16 bit size and boolean32, 32, coño.  (longint is ok.) ---------------------------------------------------------------------- Martin_fr · 2025-01-30 01:03 Quote from: Fred vS on January 30, 2025, 01:29:36 amCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i varabol : boolean32;...beginabol := boolean32(123456789);  // the integer > 0 that will set abol as "true"  I didn't pay much attention to the example, sorry... But, it is wrong. The comment is wrong. It would be true for a LongBool. But a boolean32 is only true if set to the ordinal value 1. Any value other than 0 or 1 will set it to undefined. ---------------------------------------------------------------------- Fred vS · 2025-01-30 01:20 Quote from: Martin_fr on January 30, 2025, 02:03:04 amQuote from: Fred vS on January 30, 2025, 01:29:36 amCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i varabol : boolean32;...beginabol := boolean32(123456789);  // the integer > 0 that will set abol as "true"  I didn't pay much attention to the example, sorry... But, it is wrong. The comment is wrong. It would be true for a LongBool. But a boolean32 is only true if set to the ordinal value 1. Any value other than 0 or 1 will set it to undefined. Ha, I miss something then. This: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i varabol : boolean32;...begin  abol := boolean32(-123456789); // <> 0 = true writeln(longint(abol)); if abol then writeln('it is true');... gives that as result: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i -123456789it is true ---------------------------------------------------------------------- Martin_fr · 2025-01-30 01:28 Yes undefined behaviour can print true. But see the code here https://forum.lazarus.freepascal.org/index.php/t opic,70004.msg545161.html#msg545161 ---------------------------------------------------------------------- Fred vS · 2025-01-30 01:52 Quote from: Martin_fr on January 30, 2025, 02:28:42 amYes undefined behaviour can print true. But see the code here https://forum.lazarus.freepascal.org/index.php/t opic,70004.msg545161.html#msg545161 OK, thanks (and I have to confess that I have problem with the concept of boolean (0 or 1, true or false, plus or minus, black or white). Binary in fact does not exist in reality, see math, electric, ..., it is -, 0, + (ternary not binary). But this is a other story. ---------------------------------------------------------------------- 440bx · 2025-01-30 03:12 Quote from: Martin_fr on January 30, 2025, 02:03:04 amBut a boolean32 is only true if set to the ordinal value 1. Any value other than 0 or 1 will set it to undefined. That really begs the question: why does the compiler allow it to be set to an "undefined" value when it has all the necessary information to prevent it ? The compiler doesn't even emit a hint or a warning to draw the programmer's attention to the incorrect/invalid/"undefined territory" (choose whichever adjective is more palatable) situation.  Emitting a hint or warning should be acceptable... no ? (or do we want to hide the fact that booleans can be set to values other than 0 and 1 under the binary rug ?) Basically, if the programmer creates a statement the compiler should reject, it's not a flaw that the compiler didn't reject the incorrect statement, the real problem is: the programmer should not have found that flaw.. much less use it in spite of the fact that the compiler pretends it is perfectly acceptable. Anyway, what's really sad is that because Delphi has the same "deficiency", FPC will use that as the reason to keep it that way. However, on a related note, shouldn't the documentation be updated to inform the programmer of the fact that booleans may be set to values other than TRUE and FALSE but those are the only values that will produce correct results.  That's the reality, the documentation should "probably" reflect that. ---------------------------------------------------------------------- dsiders · 2025-01-30 03:20 Quote from: 440bx on January 30, 2025, 04:12:23 amHowever, on a related note, shouldn't the documentation be updated to inform the programmer of the fact that booleans may be set to values other than TRUE and FALSE but those are the only values that will produce correct results.  That's the reality, the documentation should "probably" reflect that. Did you submit a patch? ---------------------------------------------------------------------- 440bx · 2025-01-30 03:33 Quote from: dsiders on January 30, 2025, 04:20:24 amDid you submit a patch? No, because I do not believe that anything is going to change.  I believe that both, the compiler and the documentation will remain _exactly_ the way they are with, in the best case, _one_ possible exception which is: the compiler might be enhanced to emit a hint or warning if an invalid cast to boolean is made.  Honestly, I would be surprised if that happened (pleasantly though.)