[SOLVED] Cannot create lookup table with UInt64 values without errors lazarus / 62-General ---------------------------------------------------------------------- flowCRANE · 2022-08-25 10:54 I need to create some fixed-size lookup table with unsigned 64-bit values, like in the example below: 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}{$LONGSTRINGS ON} const  LOOKUP_TABLE: array [0 .. 1] of UInt64 = ($FEDCBA9876543210, $FEDCBA9876543210);beginend. But the compiler is treating such literals as signed integers and displays warnings about range check errors: 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 Warning: range check error while evaluating constants (-81985529216486896 must be between 0 and 18446744073709551615)Warning: range check error while evaluating constants (-81985529216486896 must be between 0 and 18446744073709551615) This example uses default compiler settings and it is compilable (only warnings are emitted). But in my main project, I have custom compiler settings and such a table declaration gives me errors, so the code cannot be compiled at all. To avoid problems, I have to disable range checking and turn off warnings: 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 {$PUSH}{$RANGECHECKS OFF}{$WARNINGS    OFF} const  LOOKUP_TABLE: array [0 .. 1] of UInt64 = ($FEDCBA9876543210, $FEDCBA9876543210); {$POP} And such a code can be compiled without errors and warnings. My question is — why the FPC is treating the literals as signed integers, despite the fact that it knows what data type is used by the array? ---------------------------------------------------------------------- MarkMLl · 2022-08-25 11:03 Quote from: furious programming on August 25, 2022, 12:54:50 pmAnd such a code can be compiled without errors and warnings. My question is — why the FPC is treating the literals as signed integers, despite the fact that it knows what data type is used by the array? Design decision. It knows that the LHS of the assignment is unsigned but is treating the RHS as signed and then attempting a cast: try putting explicit qword() casts on the RHS numeric literals. MarkMLl ---------------------------------------------------------------------- flowCRANE · 2022-08-25 11:33 Quote from: MarkMLl on August 25, 2022, 01:03:38 pmDesign decision. It knows that the LHS of the assignment is unsigned but is treating the RHS as signed and then attempting a cast […] Thank you for the clarification. So this is the design decision. Quote[…] try putting explicit qword() casts on the RHS numeric literals. Yep, I can do this to ommit warnings, but my target array contains hundreds of numbers, so if I add explicit casting, its implementation will be super long — that's why I'm trying to reduce the amout of the code needed. Finally, I decided to use compiler directives — short syntax and no warnings and errors. Again, thanks for the answer. ---------------------------------------------------------------------- PascalDragon · 2022-08-25 11:35 Quote from: furious programming on August 25, 2022, 12:54:50 pmMy question is — why the FPC is treating the literals as signed integers, despite the fact that it knows what data type is used by the array? And here is your problem: Pascal as a language does (in general) not care about the left side, so even if the compiler knows that it parses constants for an unsigned 64-bit integer it must not act upon it, because the right side must be parsed as is and as Pascal as a language prefers signed types the constants are parsed as signed 64-bit integers. Thus there will be complains by the compiler. If you don't want these complains then you need to cast to QWord or UInt64 as MarkMLI mentioned (or disable the message). ---------------------------------------------------------------------- MarkMLl · 2022-08-25 11:58 Quote from: furious programming on August 25, 2022, 01:33:00 pmYep, I can do this to ommit warnings, but my target array contains hundreds of numbers, so if I add explicit casting, its implementation will be super long — that's why I'm trying to reduce the amout of the code needed. Finally, I decided to use compiler directives — short syntax and no warnings and errors. Define a macro Q as qword, then it only adds three chars per number. @PascalDragon Is there any case where there is a risk of a substring match here? If so is there a workaround? I've used QQ as a macro to condense a particular quoting case being used repeatedly in the past, but OP appears vehement about the length aspect. MarkMLl ---------------------------------------------------------------------- MarkMLl · 2022-08-25 12:00 Quote from: PascalDragon on August 25, 2022, 01:35:32 pmAnd here is your problem: Pascal as a language does (in general) not care about the left side, so even if the compiler knows that it parses constants for an unsigned 64-bit integer it must not act upon it, because the right side must be parsed as is and as Pascal as a language prefers signed types the constants are parsed as signed 64-bit integers. Although you did point out to me a few days ago that there were exceptions to this, so that e.g. the appropriate overloaded assignment can be chosen. I admit to being uncomfortable with this... MarkMLl ---------------------------------------------------------------------- nanobit · 2022-08-25 12:34 Quote from: furious programming on August 25, 2022, 12:54:50 pmI need to create some fixed-size lookup table with unsigned 64-bit values, like in the example below: The comments about RHS type at compiletime (and how to resolve this) are right because implicit conversion (to Uint64 in this case) would diminish type strictness and should be the exception. But FPC still has a (known) bug here: the signed interpretation of 64-bit hex literals. 1) The FPC (and also Delphi) documentation says differently (unsigned): https://www.freepascal.org/docs-html/ref/refse6.html 2) a longer note (pdf) about FPC hexadecimal literals can be found here ---------------------------------------------------------------------- Thaddy · 2022-08-25 12:59 A workaround is to explicitly cast the literals: 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 const  LOOKUP_TABLE: array [0 .. 1] of uint64 = (uint64($FEDCBA9876543210), uint64($FEDCBA9876543210));beginend.Just to make the warnings disappear. Code is not affected. ---------------------------------------------------------------------- flowCRANE · 2022-08-25 13:28 I chose compiler directives because thanks to them I don't have to use casting. I do not want to cast, because the readability of the table contents will be low, nor will macros, because they only obscure the code and make it difficult to analyze (I don't like abstractions). I asked mostly because I was curious about how the compiler treats literals and where the problem with range checking comes from. Thank you for your answers on this topic. ---------------------------------------------------------------------- Thaddy · 2022-08-25 13:47 Well: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 const{$push}{$warn 4110 off}{$R-}  LOOKUP_TABLE: array [0 .. 1] of uint64 = ($FEDCBA9876543210, $FEDCBA9876543210); {$pop}beginend. Might suit you? It is more specific than {$warnings off} which may bite you. ---------------------------------------------------------------------- MarkMLl · 2022-08-25 14:01 Well, coding styles vary but to be blunt I consider using a directive to be the worst possible choice here since it will apply to /all/ code generated while the directive is in effect, not just to the particular literal causing the problem. MarkMLl ---------------------------------------------------------------------- flowCRANE · 2022-08-25 19:04 @Thaddy: see the first post in this thread — I gave a similar code as one of the solutions. @MarkMLI: that would be a problem if I turned off range-checking and warnings somewhere in the code, but turned them back on nowhere. And it is not — these directives are turned off only for the purpose of array declaration, and right after it is restoring the previous compiler settings (ie {$POP}). I found such a solution in the crc.pp unit, where the directives given in the first post of this thread are used to declare a lookup tables for the CRC32 and CRC64 calculation functions. They were my inspiration. ---------------------------------------------------------------------- Thaddy · 2022-08-27 10:38 Quote from: MarkMLl on August 25, 2022, 04:01:03 pmWell, coding styles vary but to be blunt I consider using a directive to be the worst possible choice here since it will apply to /all/ code generated while the directive is in effect, not just to the particular literal causing the problem. MarkMLl No, I used push/pop  It is only in effect on that particular declaration. OP did the same btw, but he removed all warnings, albeit temporary, but best practice is just to remove the offending warning. ---------------------------------------------------------------------- Thaddy · 2022-08-27 10:42 Quote from: furious programming on August 25, 2022, 09:04:41 pm@Thaddy: see the first post in this thread — I gave a similar code as one of the solutions. Yes, I know that, but my code is way more specific. {$Warnings off} is a nono, if you know that you just need it for the particular case you described. ---------------------------------------------------------------------- flowCRANE · 2022-08-28 15:13 Quote from: Thaddy on August 27, 2022, 12:42:08 pmYes, I know that, but my code is way more specific. Yep, you are right — your solution works the same as mine, but is safer. Thanks. ---------------------------------------------------------------------- PascalDragon · 2022-08-28 15:36 Quote from: MarkMLl on August 25, 2022, 01:58:46 pm@PascalDragon Is there any case where there is a risk of a substring match here? If so is there a workaround? I've used QQ as a macro to condense a particular quoting case being used repeatedly in the past, but OP appears vehement about the length aspect. Macros are only matched on a full token. Quote from: MarkMLl on August 25, 2022, 02:00:53 pmQuote from: PascalDragon on August 25, 2022, 01:35:32 pmAnd here is your problem: Pascal as a language does (in general) not care about the left side, so even if the compiler knows that it parses constants for an unsigned 64-bit integer it must not act upon it, because the right side must be parsed as is and as Pascal as a language prefers signed types the constants are parsed as signed 64-bit integers. Although you did point out to me a few days ago that there were exceptions to this, so that e.g. the appropriate overloaded assignment can be chosen. I admit to being uncomfortable with this... The only exception to the rule are assignments of functions to function variables (and methods to method variables, etc.), because otherwise this simply wouldn't work with overloads which are a huge part of Object Pascal. ---------------------------------------------------------------------- MarkMLl · 2022-08-28 16:52 Quote from: PascalDragon on August 28, 2022, 05:36:14 pmThe only exception to the rule are assignments of functions to function variables (and methods to method variables, etc.), because otherwise this simply wouldn't work with overloads which are a huge part of Object Pascal. I'm thinking of your QuoteFor the assignment operator (and maybe also other operator overloads returning a custom type) the compiler does take the left side into account, after all it wouldn't be able to pick the correct one otherwise: from https://forum.lazarus.freepascal.org/index.php/topic,60218.msg450 486.html#msg450486 (#43) which I don't think involve function/method variables. Apologies for hammering at this one, but while I'm sure that it's me not really understanding things I might not be the only one. MarkMLl ---------------------------------------------------------------------- PascalDragon · 2022-08-29 12:04 Quote from: MarkMLl on August 28, 2022, 06:52:14 pmI'm thinking of your QuoteFor the assignment operator (and maybe also other operator overloads returning a custom type) the compiler does take the left side into account, after all it wouldn't be able to pick the correct one otherwise: from https://forum.lazarus.freepascal.org/index.php/topic,60218.msg450 486.html#msg450486 (#43) which I don't think involve function/method variables. Apologies for hammering at this one, but while I'm sure that it's me not really understanding things I might not be the only one. Right... forgot about assignment operators... But they have the same reason as function pointers: they would not be usable otherwise. ---------------------------------------------------------------------- MarkMLl · 2022-08-29 12:39 Quote from: PascalDragon on August 29, 2022, 02:04:33 pmRight... forgot about assignment operators... But they have the same reason as function pointers: they would not be usable otherwise. OK, thanks for that. Considering https://www.freepascal.org/docs- html/current/ref/refse104.html#x224-24800015.3, presumably that applies to both := and explicit (is that now a reserved word? ** ). I've got into moderately deep water with this in the past, so am being cautious. I ended up having to use a byte move operation inside the overloaded function to avoid a recursion... that was probably in 2.4 days so behaviour might have been changed since. Is there any way of saying "this type must never be implicitly cast"? MarkMLl ** ...and is it the modern adjective with a soft c, or the Latin verb with a hard c? ---------------------------------------------------------------------- PascalDragon · 2022-08-30 07:18 Quote from: MarkMLl on August 29, 2022, 02:39:36 pmQuote from: PascalDragon on August 29, 2022, 02:04:33 pmRight... forgot about assignment operators... But they have the same reason as function pointers: they would not be usable otherwise. OK, thanks for that. Considering https://www.freepascal.org/docs- html/current/ref/refse104.html#x224-24800015.3, presumably that applies to both := and explicit (is that now a reserved word? ** ). Explicit isn't a reserved word. It's simply the name that Delphi also uses for that operator overload (but they use names for all the operators, e.g. Add instead of +, or Implicit instead of :=). Quote from: MarkMLl on August 29, 2022, 02:39:36 pmI've got into moderately deep water with this in the past, so am being cautious. I ended up having to use a byte move operation inside the overloaded function to avoid a recursion... that was probably in 2.4 days so behaviour might have been changed since. Well, yes, one definitely needs to be careful when writing operator overloads. Quote from: MarkMLl on August 29, 2022, 02:39:36 pmIs there any way of saying "this type must never be implicitly cast"? In that case you only overload the Explicit operator. This one is used when you have a typecast (if it isn't defined than the := operator is used, if available): 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 topovld; {$mode objfpc}{$H+}{$modeswitch advancedrecords} type  TTest = record    f: LongInt;    class operator Explicit (const aArg: TTest): LongInt;  end; class operator TTest.Explicit(const aArg: TTest): LongInt;begin  Result := aArg.f;end; var  t: TTest;  l: LongInt;begin  t.f := 42;  //l := t; // incompatible types  l := LongInt(t);end. Quote from: MarkMLl on August 29, 2022, 02:39:36 pm** ...and is it the modern adjective with a soft c, or the Latin verb with a hard c? I'd say the modern adjective, cause it's essentially “explicit assignment” and “implicit assignment”. ---------------------------------------------------------------------- MarkMLl · 2022-08-30 08:42 Quote from: PascalDragon on August 30, 2022, 09:18:57 amExplicit isn't a reserved word. It's simply the name that Delphi also uses for that operator overload (but they use names for all the operators, e.g. Add instead of +, or Implicit instead of :=). ... I'd say the modern adjective, cause it's essentially “explicit assignment” and “implicit assignment”. Thanks for that, makes sense in view of the longform names. QuoteIn that case you only overload the Explicit operator. This one is used when you have a typecast (if it isn't defined than the := operator is used, if available): It's the fallback to := plus the possibility of automatic casting that worries me, at least for "number-like" quantities. Can I assume that if both explicit and implicit are overloaded then there will never be an automatic cast? If that is correct, does it have to be done for all combinations or is defining the source type adequate? I'm not sure that question makes sense... at the very least I think I've got a bit better grip of what the use cases are and I already know to be careful. I definitely agree that overloads are important. We obviously disagree on the desirability (not to mention practicality) of extending them to arbitrary user-defined operators, and the risks of automatic casting. MarkMLl ---------------------------------------------------------------------- PascalDragon · 2022-08-30 11:45 Quote from: MarkMLl on August 30, 2022, 10:42:44 amQuoteIn that case you only overload the Explicit operator. This one is used when you have a typecast (if it isn't defined than the := operator is used, if available): It's the fallback to := plus the possibility of automatic casting that worries me, at least for "number-like" quantities. Can I assume that if both explicit and implicit are overloaded then there will never be an automatic cast? If that is correct, does it have to be done for all combinations or is defining the source type adequate? I'm not sure that question makes sense... at the very least I think I've got a bit better grip of what the use cases are and I already know to be careful. Any “automatic cast” is an internal operator that the compiler knows about. You can't overload operators for which an internal one exists (and for assignments this includes both implicit and explicit). So you wouldn't be able to overload the conversion from LongInt to Word for example, no matter if implicit or explicit. ---------------------------------------------------------------------- MarkMLl · 2022-08-30 12:15 Quote from: PascalDragon on August 30, 2022, 01:45:34 pmAny “automatic cast” is an internal operator that the compiler knows about. You can't overload operators for which an internal one exists (and for assignments this includes both implicit and explicit). So you wouldn't be able to overload the conversion from LongInt to Word for example, no matter if implicit or explicit. OK, which I think fits in with my "number-like" comment. Possibly with a few more complex cases hardcoded into the compiler even if the implementation is in the RTL. So once you're talking about more complex entities, starting off with complex numbers etc., implicit assignment (AKA :=) and explicit casts (AKA an implicit function named for the destination type) are completely unambiguous. MarkMLl ---------------------------------------------------------------------- PascalDragon · 2022-08-31 07:04 Quote from: MarkMLl on August 30, 2022, 02:15:00 pmSo once you're talking about more complex entities, starting off with complex numbers etc., implicit assignment (AKA :=) and explicit casts (AKA an implicit function named for the destination type) are completely unambiguous. Essentially, yes. Though please don't name explicit assignments “implicit function named for the destination type”. It's a typecast, not some kind of function. It may look syntactically like a function, but semantically it's not. ---------------------------------------------------------------------- MarkMLl · 2022-08-31 07:39 Quote from: PascalDragon on August 31, 2022, 09:04:26 amEssentially, yes. Though please don't name explicit assignments “implicit function named for the destination type”. It's a typecast, not some kind of function. It may look syntactically like a function, but semantically it's not. It was the /appearance/ that interested me at that point: I was looking for a descriptive turn of phrase compatible with the concepts expressed in J&W Pascal in order to be completely unambiguous. I'm not entirely sure where casting etc. originated in Pascal terms: I don't think it was in the most influential editions of J&W. While I think casts existed- with slightly different syntax- in C ab initio, Wirth introduced the concept in Modula-2 as a "type transfer"... I presume that either UCSD or Turbo Pascal (which had a sibling Modula-2) did the same at roughly the same time. MarkMLl ---------------------------------------------------------------------- PascalDragon · 2022-08-31 11:52 Quote from: MarkMLl on August 31, 2022, 09:39:56 amQuote from: PascalDragon on August 31, 2022, 09:04:26 amEssentially, yes. Though please don't name explicit assignments “implicit function named for the destination type”. It's a typecast, not some kind of function. It may look syntactically like a function, but semantically it's not. It was the /appearance/ that interested me at that point: I was looking for a descriptive turn of phrase compatible with the concepts expressed in J&W Pascal in order to be completely unambiguous. I'm not entirely sure where casting etc. originated in Pascal terms: I don't think it was in the most influential editions of J&W. While I think casts existed- with slightly different syntax- in C ab initio, Wirth introduced the concept in Modula-2 as a "type transfer"... I presume that either UCSD or Turbo Pascal (which had a sibling Modula-2) did the same at roughly the same time. The Free Pascal Lanugage Reference Guide calls them “Typecasts”, so please use that in context of FPC.