[fpc-pascal] Understanding error messages in static linking
Hello, I am trying to statically link OpenSSL. I'm using the Win64 full installer from https://slproweb.com/products/Win32OpenSSL.html which includes precopmiled static libraries which were compiled with VC using the /MT, /MD, /MTd and /MDd switches. This obviously stands for: /MDCreates a multithreaded DLL using MSVCRT.lib. /MDd Creates a debug multithreaded DLL using MSVCRTD.lib. /MTCreates a multithreaded executable file using LIBCMT.lib. /MTd Creates a debug multithreaded executable file using LIBCMTD.lib. So using the MD version seems to be most logical to me. FPC is 3.3/trunk, but not the most recent one (about 2 months old). Trial 1: program project1; {$linklib z:/libcrypto_static.lib} begin end. Result: `Error: Invalid DLL z:\libcrypto_static.lib, Dos Header invalid` The message reads like a DLL has to be specified. Trial 2: program project1; {$linklib z:/libcrypto-3-x64.dll} begin end. Result: `project1.lpr(6,1) Error: Import library not found for z:\libcrypto-3-x64` Strange. Because the file is there... Trial 3: I'm now using `objconv` from https://github.com/gitGNU/objconv/blob/master/objconv-x64.exe Conversion: `objconv-x64.exe -fcoff libcrypto_static.lib libcrypto_static.a` (interestingly, using `-fCOFF` as printed on the help page doesn't work) Result: `Input library: libcrypto_static.lib, Format: COFF64, Output: libcrypto_static.a, Format: COFF64` So it's converting from COFF to COFF. Okay. Now we have a new minimal example: program project1; {$linklib z:/libcrypto_static.a} begin end. At least it gives no errors. But I haven't used anything from libcrypto yet, so let's go to... Trial 4: program project1; uses CTypes; {$linklib z:/libcrypto_static.a} function OPENSSL_init_crypto(opt: cuint64; const settings: pointer): CInt; cdecl; external; begin OPENSSL_init_crypto (0, nil); // parameters aren't important right now end. Result: `project1.lpr(7,1) Error: Invalid ar member lfn name index in z:\libcrypto_static.a` Googling this error gives 1 result: It is the source code line of this error message, so it doesn't seem to be a very common problem :) Trial 5: Let's try changing the `external` declaration. From the FPC manual: > external ’lname’; > Then this tells the compiler that the function resides in library “lname”. > The compiler will then automatically link this library to the program. New approach: program project1; uses CTypes; function OPENSSL_init_crypto(opt: cuint64; const settings: pointer): CInt; cdecl; external 'libcrypto_static'; begin OPENSSL_init_crypto (0, nil); end. This compiles, but gives an error when executing: "...because libcrypto_static.dll was not found". One can now use `libcrypto-3-x64` instead of `libcrypto_static`, but then I have to redistribute the libcrypto DLL, which is just what I'm trying to avoid. Next idea: Trial 6: Use `objconv-x64.exe -fcoff -lx libcrypto_static.lib` to split the library into separate object files. Then I get: Member crypto\libcrypto-lib-init.obj - COFF-64 OPENSSL_cleanup OPENSSL_init_crypto OPENSSL_atexit ??_C@_0O@BNMMJHOI@crypto?2init?4c@ ??_C@_0BE@PHOHEBBN@OPENSSL_init_crypto@ Let's use this one: program project1; uses CTypes; {$L libcrypto-lib-init.obj} function OPENSSL_init_crypto(opt: cuint64; const settings: pointer): CInt; cdecl; external; begin OPENSSL_init_crypto (0, nil); end. Result: `project1.lpr(7,1) Error: Associative or exact match COMDAT sections are not yet supported (symbol: .debug$S)` And this is the point where I'm completely stuck. Is there anything I can try or is it just impossible to create an .exe which doesn't depend need the libcrypto DLL? Please, I don't want to discuss the pros and cons about static linking. There are no high-security demands I have to satisfy. I'd just like to understand what I'm doing wrong. Kind regards, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] JSON-Schema added
Great! Is this Json Typedef as described here? https://jsontypedef.com/ Thomas - Original Message - From: Michael Van Canneyt via fpc-pascal To: Lazarus mailing list Sent: Saturday, August 17, 2024, 16:52:32 Subject: [fpc-pascal] JSON-Schema added Hi, I added a JSON-Schema class to FPC. It currently supports the latest JSON-Schema draft (2020-12) There also is a validator class. There is a testsuite, but testsuites only go so far, so I'd appreciate some feedback from people who have need for JSON-schema. (in particular, the $ref handling is a bit hairy. Available documentation is definitely lacking in clarity) The next step is adding support for OpenApi (AKA swagger). Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Documentation typo?
Hello, in `https://www.freepascal.org/docs-html/current/rtl/sockets/netaddrtostr6.html`, it is written: NetAddrToStr6 converts the IPV6 network address in Entry to a string representation in human-readable form. Basically, it is the same as NetAddrToStr6, but with the bytes in correct order. I think that the second "NetAddrToStr6" should be something else, probably "HostAddrToStr6". ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
> For constants, the compiler will choose a type and consequently the > precision. > Jonas and others have explained the rules that the compiler uses. > > If you don't like the rules that the compiler uses, you can set a type for > your > constants. When you explicitly set a type, you are also specifying the > precision of the > calculation. If the ruleset won't change - and from what I've read from the developers, it won't change - could we please have the compiler issue a warning (or a hint) if a loss in precision happens. E.g. "Warning: constant reduced to single precision. Use {$MINFPCONSTPREC} or Double() to keep full precision." I am aware about this behavior now, but nevertheless I'd like to get warned if I forget about either of those. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
Aaaah, ok. Thank you very much for alrifying this long-standing question! - Original Message - From: Tomas Hajny via fpc-pascal To: FPC-Pascal users discussions Sent: Thursday, February 22, 2024, 15:25:34 Subject: [fpc-pascal] Floating point question On 2024-02-22 15:08, Thomas Kurz via fpc-pascal wrote: >> If you're using Win64, then the answer is simple: x86_64-win64 unlike >> any >> other x86 target does not support Extended, so neither the compiler >> nor the >> code in runtime will ever calculate anything with that precision. > That's another thing I've never understood. How can it depend on the > OS? It's the CPU which does math, and I don't understand what the OS > has to do with that? If amd64 architecture didn't support the > extended-type at all, I'd say "ok". But it's supported on Linux but > not on Windows? Huh? The reason is that the operating system is among others responsible for controlling the multitasking. That includes saving the context of the originally active task and restoring the context of the new task to the original state before it was interrupted. If Win64 doesn't guarantee restoring FPU registers specific to the extended type, using this type would get you into troubles despite its support in the FPU. Tomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
> for example, here on Earth, (7 decimal places) 0.001 degree latitude is > ""only"" 1cm... (8 decimal places) 0.0001 degree latitude is ""only"" > 1mm... > longitude, on the other hand, is variable such that 7 decimal places at the > equator is the same as latitude but as you move toward the poles, it changes > such that 4 decimal places is 20cm... My initial problem (i.e. why I asked the original question -- which I do regret meanwhile *g*) was that we do use floating-point numbers for date and time operations. (TDateTime = Double) And I had discrepancies of about 40 seconds when converting between astronomical dates and TDateTime. This was how it all started... We need approx. 5 decimals to represent one second (because the non-fractional part is considered being the day number). So "single" precision isn't acceptable here. If TDateTime were Unix-timestamp, it wouldn't matter. But since TDateTime is Julian day number (maybe with an offset, but that's irrelevant here), it unfortunately does matter. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
> If you're using Win64, then the answer is simple: x86_64-win64 unlike any > other x86 target does not support Extended, so neither the compiler nor the > code in runtime will ever calculate anything with that precision. That's another thing I've never understood. How can it depend on the OS? It's the CPU which does math, and I don't understand what the OS has to do with that? If amd64 architecture didn't support the extended-type at all, I'd say "ok". But it's supported on Linux but not on Windows? Huh? ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
> But, sorry, because we are talking about compile time math, performance (nanoseconds) in this case doesn't count, IMO. That's what i thought at first, too. But then I started thinking about how to deal with it and sumbled upon difficulties very soon: a) 8427.0 + 33.0 / 1440.0 An easy case: all constants, so do the calculation at highest precision and reduce it afterwards, if possible. b) var_single + 33.0 / 1440.0 Should also be feasable by evaluating the constant expression first, then reducing it to single (if possible) and adding the variable in the end. c) 8427.0 + var_double / 1440.0 Because of using the double-type variable here, constants should be treated as double even at the cost of performance due to not knowing whether the result will be assigned to a single or double. d) 8427.0 + var_single / 1440.0 And this is the one I got to struggle with. And I can imagine this is the reason for the decision about how to handle decimal constants. My first approach would have been to implicitly use single precision values throughout the expression. This would mean to lose precision if the result will be assigned to a double-precision variable. One could say: "bad luck - if the programmer intended to get better precision, he should have used a double-precision variable as in case c". But this wouldn't be any better than the current state we have now. Overall, I must admit that the choice ain't easy at all. In this situation, it might be a good choice to ask "what would other languages do here?". As far as I know about C, it treats constants as double-precision by default. You have to write "1.0f" if you explicitly want single precision. But I think it's too late for introducing yet another change. Imho, the correct decision at FPC v2.2 would have been to keep the previous behavior and instruct those concering performance to use "{$MINFPCONSTPREC 32}" (or using the "1.0f" notation) instead of requiring everyone to use "{$MINFPCONSTPREC 64}" to keep compatibility with previous releases. Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
>> You cannot do this in Pascal. The evaluation of the expression on the >> right of := does not >> know (and should not know) what the type is of the expression on the left. > It's even theoretically impossible to do in case the result is passed to > a function or intrinsic that is overloaded with single/double/extended > parameters. In other cases, I got a "can't determine which overloaded function to call" error, so I think this should be handable; but I understand the first argument of course. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
I wouldn't say so. Or at least, not generally. Why can't the compiler do what the programer intends to do: var s: single; d: double; e: extended; begin s := 8427.0 + 33.0 / 1440.0; // treat all constants all "single" d := 8427.0 + 33.0 / 1440.0; // treat all constants all "double" e := 8427.0 + 33.0 / 1440.0; // treat all constants all "extended" end. Shouldn't this satisfy all the needs? Those caring for precision will work with double precision and don't have to take care for a loss in precision. Those caring for speed can use the single precision type and be sure that no costly conversion to double or extended will take place. - Original Message - From: Jonas Maebe via fpc-pascal To: fpc-pascal@lists.freepascal.org Sent: Sunday, February 11, 2024, 23:29:42 Subject: [fpc-pascal] Floating point question On 11/02/2024 23:21, Bernd Oppolzer via fpc-pascal wrote: > and this would IMHO be the solution which is the easiest to document and > maybe to implement > and which would satisfy the users. And generate the slowest code possible on most platforms. Jonas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] "Unexpected end of file" when having an open comment after the final "end."
Hello Martin, I've been using Pascal for more than 30 years now, but I must admit I've never before seen the construct you posted. And it doesn't compile either: project1.lpr(4,4) Error: Syntax error, "." expected but ";" found Kind regards, Thomas - Original Message - From: Martin Wynne via fpc-pascal To: fpc-pascal@lists.freepascal.org Sent: Thursday, February 8, 2024, 20:01:17 Subject: [fpc-pascal] "Unexpected end of file" when having an open comment after the final "end." Hi Thomas, The error is not the file content after "end.". The error is not having the expected "end;" after "begin". This works ok: _ program test; begin end; end. abc 123 _ Martin. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] "Unexpected end of file" when having an open comment after the final "end."
Hello all, I'm unsure about whether or not to report this as a bug. Imho, it is a bug, but maybe there's a good reason to handle this. Please take the following example: ---start--- program test; begin end. { ---end--- Result: Z:\>ppc386.exe testproj.pas Free Pascal Compiler version 3.2.2 [2022/05/15] for i386 Copyright (c) 1993-2021 by Florian Klaempfl and others Target OS: Win32 for i386 Compiling testproj.pas testproj.pas(6,1) Fatal: Unexpected end of file Fatal: Compilation aborted I'd say the code should compile without any errors for the following reasons: 1. The "end." tells the compiler that the file is finished here. Whatever comes after this should not be considered by the compiler. 2. The compiler doesn't consider any other statement after "end.". For example, replacing the open comment with something like "vra" doesn't cause an error either. Kind regards, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
I think the reason why this new behavior doesn't occur with 1440.1 is that this number cannot be reduced to "single" precision. It will keep "double" precision. Consider this instead: program TESTDBL1 ; var TT : double ; EE: double; begin (* HAUPTPROGRAMM *) TT := 8427 + 33 / 1440.5 ; EE := Double(8427) + Double(33) / Double(1440.5); WRITELN ( 'tt=' , TT : 20 : 20 ) ; WRITELN ( 'ee=' , EE : 20 : 20 ) ; end (* HAUPTPROGRAMM *) . Result: tt=8427.022460937500 ee=8427.0229087122534000 So it's the same as with ".0". FPC treats the constant as type "single". Imho, this is perfectly legal, but when assigning an expression to a "double" variable, an implicit cast to double should occur. When using a variable of type "single" (instead of a constant), this casting is done: program TESTDBL1 ; {$mode objfpc} var TT : double ; EE: double; x: Single = 1440.5; begin (* HAUPTPROGRAMM *) TT := 8427 + 33 / x ; EE := 8427 + 33 / Double(x); WRITELN ( 'tt=' , TT : 20 : 20 ) ; WRITELN ( 'ee=' , EE : 20 : 20 ) ; end (* HAUPTPROGRAMM *) . Prints: tt=8427.0229087122534000 ee=8427.0229087122534000 I don't know whether this is intentional or not, but I cannot see any good reason why using a constant in an expression has to be treated differently than using a variable. To me as a programmer, this behavior is unexpected. If the 2.2 change is not going to be reverted (and as far as I understand Florian correctly, it won't be changed), maybe one could at least introduce a warning about a loss of precision when using a constant of type "single" in an expression which will be assigned to a variable of type "double". Kind regards, Thomas - Original Message - From: James Richters via fpc-pascal To: 'FPC-Pascal users discussions' Sent: Tuesday, February 6, 2024, 16:23:30 Subject: [fpc-pascal] Floating point question What's apparently happening now is: MyExtended := ReducePrecisionIfNoLossOfData (8246) + ReducePrecisionIfNoLossOfData (33.0) / ReducePrecisionIfNoLossOfData (1440.0); But it is not being done correctly, the 1440.0 is not being reduced all the way to an integer, because it was, everything would work. The 1440.0 is being considered a single, and the division is also being now considered a single, even though that is incorrect. But 1440.1 is not being considered a single, because 1440.1 is not breaking everything. What should be happening is: MyExtended := ReducePrecisionIfNoLossOfData(8246+33.0/1440.0); I just realized something... regardless of when or how the reduction in precision is happening, the bug is different than that, because the result of a byte divided by a single when stored in a double is a double, NOT a single, there should be no problem here, there is a definite bug. Consider this: program TESTDBL1 ; Const HH = 8427.02291667; Var AA : Integer; BB : Byte; CC : Single; DD : Single; EE : Double; FF : Extended; GG : Extended; begin AA := 8427; BB := 33; CC := 1440.0; DD := AA+BB/CC; EE := AA+BB/CC; FF := AA+BB/CC; GG := 8427+33/1440.0; WRITELN ( 'DD = ',DD: 20 : 20 ) ; WRITELN ( 'EE = ',FF: 20 : 20 ) ; WRITELN ( 'FF = ',FF: 20 : 20 ) ; WRITELN ( 'GG = ',GG: 20 : 20 ) ; WRITELN ( 'HH = ',HH: 20 : 20 ) ; end. When I do the division of a byte by a single and store it in an extended, I get the division carried out as an extended. FF, GG, and HH should all be exactly the same if there is not a bug. But: DD = 8427.02246100 EE = 8427.022916625000 FF = 8427.022916625000 GG = 8427.022460937500 HH = 8427.022916625000 GG, the one with constants, is doing it wrong... If the entire formula was calculated the original way at full precision, then only result was reduced if there was no loss in precision right before storing as a constant, then this solves the problems for everyone, and this is the correct way to do this. Then everyone is happy, no Delphi warnings, no needlessly complex floating point computations if the result of all the math is a byte, and no confusion as to why it works with 1440.1 and not 1440.0 Compatibility with all versions of Pascal, etc.. This calculation is only done once by the compiler, the calculation should be done at full possible precision and only the result stored in a reduced way if it makes sense to do so. The problem I have with the changes made with v2.2, is that it's obvious that the change was going to introduce a known bug at the time: "Effect: some expressions, in particular divisions of integer values by floating point constants, may now default to a lower precision than in the past." How is this acceptable or the default?? "Remedy: if more precision is required than the default, typecast the floating point constant to a higher precision type, e.g. extended(2.0). Alternatively, you can use the -CF command line option to change the default pr
Re: [fpc-pascal] Floating point question
Well, this is funny because I *did* compile it on DOS with Turbo Pascal 5.5, and I got the correct result there. Cross-compiling with FPC to msdos target gave the "wrong" (aka unexpected) result again. There were so many factors involved which caused great confusion. >From my point of view, an expression being an assigned to a variable of type >"double" should be evaluated with double precision, not single. This is >obviously the way integers are handled by internally using int64. A few weeks >ago, I had incosistent behavior between x64 and x86 modes and it turned out >that 32-bit code did internal castings to int64 thus resulting in the expected >value whereas 64-bit cannot cast to int128 (because there is no int128) and >thus gives an unexpected result (well, at least to me). So my intuition would >(and obviously did!) expect double precision throughout the calculation. Kind regards, Thomas - Original Message - From: James Richters To: 'FPC-Pascal users discussions' Sent: Tuesday, February 6, 2024, 13:44:37 Subject: [fpc-pascal] Floating point question I don't think you were doing anything wrong, that's what I am simply trying to point out. If you ran your code on Turbo Pascal 7.0, you would not have an issue, it would be fine. There is no reason for a programmer to expect this behavior and it's very confusing when it does come up. There is a bug here and it should be acknowledged instead of defended. Discovering bugs is a good thing, it can lead to improvements to make the system better for everyone, but only if the discovery is learned from and acted upon. I'm sure everyone here can relate to how frustrating it can be to encounter a bug and have no idea whatsoever what the problem is. Undiscovered bugs are much worse than those which have been figured out. I think this is one that can be very frustrating for a lot of people, and it's very difficult to figure out what's happening, because everything happens correctly >99.9% of the time. If you put anything from x.001 to x.999 it has no problem, if you put x.0, you have a problem. Put as many decimals as you like to see why there is no reason why any programmer should expect this behavior. On top of that x has no problem, and many programmers use x.0 when x would have been fine, they are just in the habit of putting the .0 and in Turbo Pascal, there was never a problem with doing this. I am glad we at least have an explanation, but how many others are going to need to re-discover this issue that should not even be an issue? It can still be a problem for people who didn't happen to come across this. I didn't expect it to be an issue. While compiling with -CF64 or using {$MINFPCONSTPREC 64} fixes it for programs that use doubles, there is no good solution I can find for programs that use extended, because you can't put 80 into either of those. So for extended programs the only solution I can think of at the moment is to go through the WHOLE thing and replace all the x.0's with x Which I have started doing but it's a tedious chore. I appreciate the discussion here, because I had noticed inaccuracies from time but I was never able to get far enough in to realize this is what was happening. It's very frustrating indeed and I think if something can be done to save others this frustration and unexpected behavior, it would be helpful. James -Original Message- From: fpc-pascal On Behalf Of Thomas Kurz via fpc-pascal Sent: Tuesday, February 6, 2024 6:59 AM To: 'FPC-Pascal users discussions' Cc: Thomas Kurz Subject: Re: [fpc-pascal] Floating point question I'd like to apologize, because my intention hasn't been to raise controverse discussions. I'm very thankful about the explanation. From the beginning, I knew that the error was on my side, but I didn't know *what* I'm doing wrong. Again, thanks for helping. Kind regards, Thomas - Original Message - From: James Richters via fpc-pascal To: 'FPC-Pascal users discussions' Sent: Sunday, February 4, 2024, 18:25:39 Subject: [fpc-pascal] Floating point question I agree with Aadrian 100% "New behaviour: floating point constants are now considered to be of the lowest precision which doesn't cause data loss" We are getting data loss So it's doing it WRONG. So we are all living with a stupid way of doing things so some Delphi code won't have warnings? Who came up with this??? The old way was CORRECT, instead of changing it for everyone making it wrong for most users, a compiler directive should have been needed to get rid of the warnings, or ONLY applied in Mode Delphi. Not to make everything incorrect for everyone unless you add a directive. The problem with this that no one is expecting to need to add a directive to do things r
Re: [fpc-pascal] Floating point question
I'd like to apologize, because my intention hasn't been to raise controverse discussions. I'm very thankful about the explanation. From the beginning, I knew that the error was on my side, but I didn't know *what* I'm doing wrong. Again, thanks for helping. Kind regards, Thomas - Original Message - From: James Richters via fpc-pascal To: 'FPC-Pascal users discussions' Sent: Sunday, February 4, 2024, 18:25:39 Subject: [fpc-pascal] Floating point question I agree with Aadrian 100% "New behaviour: floating point constants are now considered to be of the lowest precision which doesn't cause data loss" We are getting data loss So it's doing it WRONG. So we are all living with a stupid way of doing things so some Delphi code won't have warnings? Who came up with this??? The old way was CORRECT, instead of changing it for everyone making it wrong for most users, a compiler directive should have been needed to get rid of the warnings, or ONLY applied in Mode Delphi. Not to make everything incorrect for everyone unless you add a directive. The problem with this that no one is expecting to need to add a directive to do things right. Consider this: Var MyVariable : Extended; MyVariable := 8427 + 33 / 1440.0; Since I am storing the result in an Extended, I DO NOT EXPECT the 33/1440 to be a SINGLE, that is NUTS!! I expect it to be all done in Extended. Why would anyone expect the contents of MyVariable to be butchered by storing the 33/1440 in single precision. In other words I expect the result of these both to be the same: program TESTDBL1 ; Var AA : Extended; BB : Extended; CC : Extended; DD : Extended; EE : Extended; begin AA := 8427; BB := 33; CC := 1440.0; DD := AA+BB/CC; EE := 8427+33/1440.0; WRITELN ( 'DD =' , DD : 20 : 20 ) ; WRITELN ( 'EE =' , EE : 20 : 20 ) ; end. But they are NOT DD =8427.022916625000 EE =8427.022460937500 EE is WRONG and can never be considered right. Why would ANY user with the code above expect that the 33/1440 would be done as a single, thus causing a loss of precision. Again: "New behaviour: floating point constants are now considered to be of the lowest precision which doesn't cause data loss" This was NOT done in the lowest precision which doesn't cause data loss.. we lost data We are no longer Extended precision, anything at all we use EE for is WRONG. This is CLEARLY WRONG! The default should be the old way and if you don't like the Delphi warnings, you can make a switch to do it this new stupider and WRONG way. I strongly feel this should be reverted, it's just wrong. This makes no sense to me at all. It's wrong to need to add a compiler directive to do things as they are expected by the vast majority to be, the directive should be needed for those few who even noticed the warnings in Delphi, and they were just warnings, not a substantial reduction in precision. James >But not at the price of loss in precision ! Unless an explicit compiler switch >like --fast-math is passed ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
Thank you all Finally I understand what's going wrong and can take care of that. I'm now using the "{$MINFPCONSTPREC 64}" and have the correct result. Again, thank you for pointing me to that behavior! - Original Message - From: Adriaan van Os via fpc-pascal To: FPC-Pascal users discussions Sent: Sunday, February 4, 2024, 13:50:48 Subject: [fpc-pascal] Floating point question Jonas Maebe via fpc-pascal wrote: > On 03/02/2024 18:42, James Richters via fpc-pascal wrote: >> Constants are also evaluated wrong,you don’t know what that constant >> is going to be used for, so all steps of evaluating a constant MUST be >> done in extended by the compiler, or the answer is just wrong. > See > https://wiki.freepascal.org/User_Changes_2.2.0#Floating_point_constants > and https://www.freepascal.org/daily/doc/prog/progsu19.html I think this discussion shows that the 2.2 compiler change was a bad idea (for modes other than Delphi). Regards, Adriaan van Os ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
Well, 8427.0229, that's what I want. But what I get is 8427.0224 And that's what I don't unterstand. - Original Message - From: Bernd Oppolzer via fpc-pascal To: Bart via fpc-pascal Sent: Sunday, January 28, 2024, 10:13:07 Subject: [fpc-pascal] Floating point question To simplify the problem further: the addition of 12 /24.0 and the subtraction of 0.5 should be removed, IMO, because both can be done with floats without loss of precision (0.5 can be represented exactly in float). So the problem can be reproduced IMO with this small Pascal program: program TESTDBL1 ; var TT : REAL ; begin (* HAUPTPROGRAMM *) TT := 8427 + 33 / 1440.0 ; WRITELN ( 'tt=' , TT : 20 : 20 ) ; end (* HAUPTPROGRAMM *) . With my compiler, REAL is always DOUBLE, and the computation is carried out by a P-Code interpreter (or call it just-in-time compiler - much like Java), which is written in C. The result is: tt=8427.022916667879 and it is the same, no matter if I use this simplified computation or the original tt := (8427 - 0.5) + (12 / 24.0) + (33 / 1440.0); My value is between the two other values: tt=8427.022916668000 tt=8427.022916667879 ee=8427.022916625000 The problem now is: the printout of my value suggest an accuracy which in fact is not there, because with double, you can trust only the first 16 decimal digits ... after that, all is speculative a.k.a. wrong. That's why FPC IMO rounds at this place, prints the 8, and then only zeroes. The extended format internally has more hex digits and therefore can reliably show more decimal digits. But the last two are wrong, too (the exact value is 6... period). HTH, kind regards Bernd Am 27.01.2024 um 22:53 schrieb Bart via fpc-pascal: > On Sat, Jan 27, 2024 at 6:23 PM Thomas Kurz via fpc-pascal > wrote: >> Hmmm... I don't think I can understand that. If the precision of "double" >> were that bad, it wouldn't be possible to store dates up to a precision of >> milliseconds in a TDateTime. I have a discrepancy of 40 seconds here. > Consider the following simplified program: > > var >tt: double; >ee: extended; > begin >tt := (8427 - Double(0.5)) + (12/ Double(24.0)) + > (33/Double(1440.0)) + (0/Double(86400.0)); >ee := (8427 - Extended(0.5)) + (12/ Extended(24.0)) + > (33/Extended(1440.0)) + (0/Extended(86400.0)); >writeln('tt=',tt:20:20); >writeln('ee=',ee:20:20); > end. > === > Now see what it outputs: > C:\Users\Bart\LazarusProjecten\ConsoleProjecten>fpc test.pas > Free Pascal Compiler version 3.2.2 [2021/05/15] for i386 > ... > C:\Users\Bart\LazarusProjecten\ConsoleProjecten>test > tt=8427.022916668000 > ee=8427.022916625000 > C:\Users\Bart\LazarusProjecten\ConsoleProjecten>fpc -Px86_64 test.pas > Free Pascal Compiler version 3.2.2 [2021/05/15] for x86_64 > .. > C:\Users\Bart\LazarusProjecten\ConsoleProjecten>test > tt=8427.022916668000 > ee=8427.022916668000 > On Win64 both values are the same, because there Extended = Double. > On Win32 the Extended version is a bit closer to the exact solution: > 8427 - 1/2 + 1/2 + 33/1440 = 8427 + 11/480 > Simple as that. > Bart > ___ > fpc-pascal maillist -fpc-pascal@lists.freepascal.org > https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Floating point question
Hmmm... I don't think I can understand that. If the precision of "double" were that bad, it wouldn't be possible to store dates up to a precision of milliseconds in a TDateTime. I have a discrepancy of 40 seconds here. - Original Message - From: Bart via fpc-pascal To: FPC-Pascal users discussions Sent: Saturday, January 27, 2024, 17:03:15 Subject: [fpc-pascal] Floating point question On Sat, Jan 27, 2024 at 1:40 PM Thomas Kurz via fpc-pascal wrote: > My problems are: > 1. The "writeln" in line 32 correctly prints "0." when (cross-) compiling > to win64, but "39.375" when compiling to win32 (with ppc386). On Win64 all math is done with double precision, on win32 all literal floating point values in your code will be interpreted as Extended. Cast everything to Double and the result will be the same on Win64 and Win32. -- Bart ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Floating point question
Hello, I'm facing some strange floating-point issues and cannot find what's actually wrong. OS is win64, but I'm even getting different results when targeting to win32. Please consider the following program: program test1; {$mode objfpc} function maketime (ayear, amonth, aday, ahour, aminute, asecond: integer): double; VAR y: Int64 = 0; m: Int64 = 0; d: Int64 = 0; f: Int64 = 0; y2000: Int64 = 0; ut: double; tt: double; begin y := ayear; m := amonth; d := aday; f := (14 - m) DIV 12; y2000 := ( (d - 365972956) + (1461 * (y + 100 - f)) DIV 4 + (367 * (m - 2 + 12 * f)) DIV 12 - (3 * ((y + 1000100 - f) DIV 100)) DIV 4 ); assert (y2000 = 8427); ut := (y2000 - 0.5) + (AHour / 24.0) + (AMinute / 1440.0) + (ASecond / 86400.0); tt := (8427 - 0.5) + (12/ 24.0) + (33/1440.0) + (0/86400.0); writeln ((ut - tt) * 86400.0); assert (ut = tt); result := ut; end; var t: double; diff: double; begin t := maketime (2023, 1, 27, 12, 33, 0); t := (8427 - 0.5) + (12/ 24.0) + (33/1440.0) + (0/86400.0); diff := (t - 8427.02291670) * 86400.0; writeln (t); writeln (diff); end. My problems are: 1. The "writeln" in line 32 correctly prints "0." when (cross-) compiling to win64, but "39.375" when compiling to win32 (with ppc386). 2. According to both C, Sqlite and Excel, the value of "t" in line 41 should be "8427.0229167". FPC gives me a difference of approximately 39/86400. Could someone point me to what I'm doing wrong, please. I have a feeling to miss the forest for the trees. Thanks, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Does the varargs specifier behave differently on 32 and 64 bit platforms?
Hello, I'm using a declaration like this TYPE TRSMControl = FUNCTION (AData: PtrInt): PtrInt; CDECL; VARARGS; VAR RSMControl: TRSMControl; to make calls to a DLL function which expects a variable number of arguments. For example: RSMControl (PtrInt(1), PtrInt(2), PtrInt(3)) On win32, this works fine. On win64, I get only the first argument correctly, the rest is garbage. Within the DLL, I subsequently access all parameters by taking the address of the first parameter and incrementing it in steps of 4 bytes (or 8 bytes on win64). I wonder whether I'm doing something wrong on the caller or callee side. The code worked reliably on win32, but I'm now trying to target win64 and am facing the problem that I cannot access the data that were passed. The CDECL calling convention should pass all arguments on the stack, and I expect subsequent arguments to be at subsequent memory addresses. Does anyone have a clue for me? Kind regards, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Daily snapshots?
Thank you. That's what I've been looking for. Maybe the documentation at https://www.freepascal.org/docs-html/user/userse76.html could be updated regarding the new URL? @Nico: Thanks for pointing me to Docker images, but I do not have Docker support on my Windows, unfortunately. I furthermore fear that it might be complicated to use a dockerized Lazarus. Is there something special I have to consider when combining FPC-trunk with Lazarus 3.0? I'd like to replace the provided FPC 3.2.2 with the latest trunk snapshot. I guess I have to recompile all packages? Is there something else I need to do? Thank you, kind regards, Thomas - Original Message - From: Marco van de Voort via fpc-pascal To: fpc-pascal@lists.freepascal.org Sent: Friday, December 29, 2023, 12:37:54 Subject: [fpc-pascal] Daily snapshots? Op 27/12/2023 om 12:38 schreef Thomas Kurz via fpc-pascal: > as it seems to take longer for the next major release, I'd appreciate if > automated snapshots could be provided either daily or weekly. > In the documentation, I found a link to > ftp://ftp.freepascal.org/pub/fpc/snapshot/trunk/ but I cannot login. I tried > with user=anynous and password=my-email-address. > I don't mind the long time for the next release, but it'd help enormously to > have the option to download an up-to-date nightly build :) The FTP site has been converted to http because many browsers deprecated the FTP protocol, try http://downloads.freepascal.org/fpc/snapshot/fixes/ ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Procedures that work like WRITELN()
I think he wants to define his own procedure. The nearest thing that comes into my mind is using ARRAY OF CONST, but the call requires square brackets, then: procedure myproc (x: string; y: array of const); begin ... end; myproc ('Hello world', ['Number 1', 'Number 2', 3, 4.0]); - Original Message - From: Michael Van Canneyt via fpc-pascal To: ja...@productionautomation.net Sent: Wednesday, December 27, 2023, 12:40:24 Subject: [fpc-pascal] Procedures that work like WRITELN() On Wed, 27 Dec 2023, James Richters via fpc-pascal wrote: > I wanted to write what I thought should be a simple procedure, just instead > of calling WRITELN() with some arguments, > call WRITELOG() with the same arguments that you would use to write to a > file, but my WRITELOG() procedure would > write to the screen and the file.. but I can't figure out how to pass all > the arguments to the two WRTIELNs. > So.. > Procedure WriteLog(Filename:String, AllOtherAurguments:); > Begin >Writeln(Filename,AllOtherAurguments); >Writeln(AllOtherAurguments); > End; > How can I make this work? Since WRITELN can take any number of many kinds > of arguments, > how can I get them all and pass them along without knowing how many or what > types they are? > How does WRITELN even work when you don't know this information? > I'm guessing there should be some way to do this, because WRITELN itself > works, but how it could > possibly work is not within my experience. > The only way I could think of would be if there were versions of WRITELN > with every combination > of possible arguments, but that seems completely unmanageable and > ridiculous, > so there must be something more advanced going on, but maybe WRTELN is > special and not something I can duplicate? Writeln() is special. You cannot duplicate it. What you can do is use WriteStr(), it has the same action as Writeln() but writes to a string instead of a file. https://www.freepascal.org/docs-html/current/rtl/system/writestr.html Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Daily snapshots?
Hello, as it seems to take longer for the next major release, I'd appreciate if automated snapshots could be provided either daily or weekly. In the documentation, I found a link to ftp://ftp.freepascal.org/pub/fpc/snapshot/trunk/ but I cannot login. I tried with user=anynous and password=my-email-address. I don't mind the long time for the next release, but it'd help enormously to have the option to download an up-to-date nightly build :) Kind regards, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Error: compilation raised exception internally
> An exception or an internal error during compilation should *always* be > reported. > Please also provide a minimal, self contained example that shows the > problem. This is not always trivial because the internal errors are sometimes quite fiddly. I have a project in which an internal error occurs sometimes. When I do a "cleanup and build" (in Lazarus), it works well. There seems to be an influence of the order in which units are compiled, because I can change code in many places without getting the internal error again. But when I change code in other units, I get the internal error, but it's clearly uncorrelated to the line at which it occurs. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] What is webasssembly?
> Does this mean I can code an application in Pascal and use webassembly to turn it into a web application? If so, could you please point me to some simple examples? Without having WebAssembly used yet: As far as I understand, that should be possible. The "entry point" is here: https://wiki.freepascal.org/WebAssembly But I'd appreciate some more (and simple) examples, too. +1 for that :) ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] msdos: unresolved external
I have to extend code from QuickBasic and am using the "msdos" target from FPC 3.2 for that purpose. The resulting exe file is linked with Microsoft Linker for DOS version 5.10. It links *.a files created both from QuickBasic and FPC. The memory model is i8086-small. Basically, it works well. I have to use file functions now (Assign, Reset, Close) and as soon as I start using any of these, linking fails with the following unresolved dependencies: Z:\SYSTEM.LIB(prt0s.asm) : error L2029: '__stklen' : unresolved external Z:\SYSTEM.LIB(prt0s.asm) : error L2029: 'PASCALMAIN' : unresolved external Z:\SYSTEM.LIB(prt0s.asm) : error L2029: '___heap' : unresolved external Z:\SYSTEM.LIB(system0s896.o) : error L2029: 'INITFINAL' : unresolved external Z:\SYSTEM.LIB(prt0s.asm) : error L2029: '___stacktop' : unresolved external Z:\SYSTEM.LIB(prt0s.asm) : error L2029: '__fpc_stackplusmaxheap_in_para' : unresolved external To me, it looks as if these were very basic code for memory management. I found (e.g.) "__fpc_stackplusmaxheap_in_para" in prt0comn.asm in which is declared "extern". But I'm unable to see which external object is responsible for it. Note that I'm *not* compiling and linking the full program with FPC, I'm only developing parts of it. The main part comes from QuickBasic. But as FPC is able to build fully working MS-DOS executables in which (I assume) it needs the criticized external dependencies as well, they should exist somewhere, shouldn't they? But what do I need to link against for them to be included? Thanks for helping, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Parse JSON
fpJson fully supports JSON: https://www.freepascal.org/docs-html/fcl/fpjson/index.html https://wiki.lazarus.freepascal.org/JSON There's also JSON support in the LGenerics package, but it's not a bundled package as far as I know. Thomas - Original Message - From: Darius Blaszyk via fpc-pascal To: FPC-Pascal users discussions Sent: Friday, June 23, 2023, 16:02:26 Subject: [fpc-pascal] Parse JSON Hi all, I've hardly done anything with JSON in Freepascal before, so apologies for the trivial question. I want to traverse an array in JSON and retrieve the elements (which I don't know what they are in advance) one by one. An example of the JSON file is given below. "keywords": { "key": "value", "key1": "value1", "key2": "value2" }, Ideally, I'd like to be able to stick to the FPC out-of-the-box library. Any help would be appreciated. Rgds, Darius ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] LoadLibrary, FreeLibrary & Threads (win32)
Dear all, I have spent 2 days now tracking an access violation in my app which I couldn't debug well because it occured somewhere where no debug info was available, but obviously during a call to FreeLibrary. I don't know whether I am allowed to do this or not, but as far as I have read from the Microsoft docs about using libraries [1,2] I didn't find a note that my approach is forbidden. (Of course, I may have overread it.) [1] https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices [2] https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya What I did is to call LoadLibrary in a different thread than the main thread. The corresponding call to FreeLibrary on the other hand was done in the main thread. Question 1: Is this legal on Windows? If not, we're finished here and you can skip the rest ;) However, if it *is* legal, I'd need some help with FPC. Here's a minimal example: *** library dummylib; uses Classes; begin end. *** program project1; uses SysUtils, Types, Classes; type TLoadLibThread = class(TThread) procedure Execute; override; var FHandle: THandle; end; procedure TLoadLibThread.Execute; begin FHandle := LoadLibrary('dummylib.dll'); end; var h: THandle = NilHandle; begin with TLoadLibThread.Create(FALSE) do begin WaitFor; h := FHandle; Free; end; Assert (h <> NilHandle); FreeLibrary (h); end. *** The call to FreeLibrary causes an "access violation writing to address $14". I also tried to follow the advice in the "multithreaded application tutorial" in the wiki ("initialize the FPC's threading system by creating a dummy thread"), but this doesn't make any difference. I assume that I have some obviouy error and am just too blind to see, so I'd appreciate someone pointing me to it. Thanks, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Legitimate use of for and break
I'm certainly not the expert in FPC's details, so maybe there'll you'll get a better answer. I just tell you my point of view. >> It's an array with a terminator >>string? Probably the length of the array should be set instead of >>doing string compares every loop. > > I need to set it in the var declaration, right? I don't quite understand this question, but of it's about the length of the array, there are two ways: a) Statically as "VAR x: array[1..6] of string" b) Dynamically: var x: array of string; // I prefer x: TStringArray instead, but this requires the classes unit IIRC begin SetLength(x, 6); // will always declare a zero-based index, i.e. x[0]..x[5] // the advantage is you can change this lateron: SetLength(x, 7); // keeps items 0..5 and adds x[6] end; > words[ss] := '~'; > Is it legitimate to set elements inside a for loop? Yes, of course. You're not allow to change the loop variable, but you can assign array values there without any problem. In fact, with larger arrays, it may even be the *only* way to do it. (Except using a different loop type like while or repeat, of course.) Imagine you want to have x^2 for x = 0...1000: var y: array[0..1000] of integer; x: integer; begin for x:=0 to 1000 do // ; I prefer: for x := Low(y) to High(y) do y[x] := x * x; end; If you couldn't do that, you'd have to write y[0] := 0; y[1] := 1; y[2] := 4; y[3] := 9; > if words[ss] = '~' then > break > ^ IS IT legitimate to use a break (or continue) inside > a for loop? As far as I know, there are different opinions about this. The clear answer to whether it's *legitimate* is YES, because that's what "break" is meant for. Whether it's elegant is a different question. In my opinion YES because it often gives better readable code than nested "if" statements inside the loop. But I've also read that using "break" is discouraged because it shows a bad choice of the loop range. Kind regards, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Freeing memory with exceptions
I do not think that this discussion is of any value. If you need to care for every byte, you'd better consider using asm. In times of e-mail clients using far more than 100 MB of disk and RAM memory or simple Android apps having several dozens of megabytes because of the included trackers, it seems ridiculous to discuss about 39 bytes! - Original Message - From: Benito van der Zander via fpc-pascal To: fpc-pascal@lists.freepascal.org Sent: Thursday, May 25, 2023, 22:49:08 Subject: [fpc-pascal] Freeing memory with exceptions Hi, > That 99.99% of people does use it, indicates they simply take the > overhead because > of the advantages that the managed types offer. Or they simply do not know about the overhead Like I was writing all my code on Windows 98, and never noticed any overhead, until I started running benchmarks on Linux. Bye, Benito On 25.05.23 07:58, Michael Van Canneyt via fpc-pascal wrote: > On Thu, 25 May 2023, Hairy Pixels via fpc-pascal wrote: >>> On May 24, 2023, at 10:11 PM, Sven Barth via fpc-pascal >>> wrote: >>> You must have $H+ on and those are AnsiStrings? Why is there >>> exception handling involved with AnsiString? I guess it needs this >>> just in case an exception is thrown somewhere in the call stack? >>> Because Ansi- and UnicodeString are managed types. *All* managed >>> types managed string types, interfaces, Variants, managed records) >>> must be finalized correctly even if an exception occurs. >> That's a problem with exceptions then, they are baked into the language >> and impose a cost on all managed types now even if we use them or >> not. Even disabling the implicit stack frames (forgot what it's >> called) doesn't >> get around this right? > Why do you insist it is a problem ? > Simply don't use managed types and don't use exceptions if you don't > like the > overhead they cause. It's still perfectly possible: avoid the sysutils > unit > and you're all set. The system unit does not use exceptions. > That 99.99% of people does use it, indicates they simply take the > overhead because > of the advantages that the managed types offer. > Which is not to say that FPC should not strive to minimize the overhead. > Conceivably there is some gain possible on non-windows platforms. > Michael. > ___ > fpc-pascal maillist - fpc-pascal@lists.freepascal.org > https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Multiple enumerators per class
It's part of generics.collections and located in fpc\3.2.2\source\packages\rtl-generics\src\* - Original Message - From: Hairy Pixels via fpc-pascal To: FPC-Pascal users discussions Sent: Friday, May 12, 2023, 14:59:11 Subject: [fpc-pascal] Multiple enumerators per class > On May 12, 2023, at 7:24 PM, Marco van de Voort via fpc-pascal > wrote: > Op 12/05/2023 om 14:16 schreef Hairy Pixels via fpc-pascal: >> Is it possible to have multiple enumerators on one class? > Yes, see e.g. TDictionary that allows iterations over keys and values and > both. There is only one default iterator, but you can have some property that > has its own iterator. Where is TDictionary located so I can see the class definition? can't seem to find it Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Record Constructors which differ in parameter lists
> I would expect the type helper to remain functional. The types are the same > for all purposes except they have a different RTTI entry. But this behaviour seems inconsistent to me. For example: With "var x:double" I can use "x.IsNan". With TDateTime, which is defined as "type TDateTime = type Double", I cannot. With strings, I can use "x.IsEmpty". With Utf8String, which is defined as "type TUtf8String = type AnsiString", I cannot. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Record Constructors which differ in parameter lists
Dear Michael, thank you for the explanation. I understand that the helper overwrites the original constructor. But... I have defined "type TSomething = type TVec3f" (note the second "type"). So from my perspective, I'd assume that the TSomethingHelper doesn't apply to TVec3f at all because TSomething is defined as a new type, not only an alias for TVec3f. - Original Message - From: Michael Van Canneyt via fpc-pascal To: Thomas Kurz via fpc-pascal Sent: Tuesday, May 9, 2023, 23:55:47 Subject: [fpc-pascal] Record Constructors which differ in parameter lists On Tue, 9 May 2023, Thomas Kurz via fpc-pascal wrote: > Hello, > let's take the following example: > program Project1; > {$MODE OBJFPC} > {$MODESWITCH ADVANCEDRECORDS} > {$MODESWITCH TYPEHELPERS} > type TVec3f = record > x, y, z: Double; > constructor Create (a1, a2, a3: Double); > end; > type TSomething = type TVec3f; > type TSomethingHelper = type helper for TSomething > constructor Create (a1, a2: Double); > end; > constructor TVec3f.Create (a1, a2, a3: Double); > begin > Self.x := a1; > Self.y := a2; > Self.z := a3; > end; > constructor TSomethingHelper.Create (a1, a2: Double); > begin > Self.x := a1; > Self.y := a2; > Self.z := 1 - a1 - a2; > end; > var f: TVec3f; > begin > f := TVec3f.Create (0.0, 0.0, 0.0); // <-- error here > end. > I get the error: > project1.lpr(35,37) Error: Wrong number of parameters specified for call to > "Create" > project1.lpr(25,30) Error: Found declaration: constructor > Create(Double;Double); > So, obviously, FPC tries to apply the helper of TSomething (which should be > decoupled from TVec3f because of the "type TVec3f" declaration) to TVec3f > which hasn't defined any constructor with 2 parameters. > Is this intended behavior or should I report it as a bug? This is intended behaviour since declarations in helpers always take precedence over the methods in the class/record. Try to add overload; to the constructor in the helper. This is a hint to the compiler that it should look for other methods. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Record Constructors which differ in parameter lists
Hello, let's take the following example: program Project1; {$MODE OBJFPC} {$MODESWITCH ADVANCEDRECORDS} {$MODESWITCH TYPEHELPERS} type TVec3f = record x, y, z: Double; constructor Create (a1, a2, a3: Double); end; type TSomething = type TVec3f; type TSomethingHelper = type helper for TSomething constructor Create (a1, a2: Double); end; constructor TVec3f.Create (a1, a2, a3: Double); begin Self.x := a1; Self.y := a2; Self.z := a3; end; constructor TSomethingHelper.Create (a1, a2: Double); begin Self.x := a1; Self.y := a2; Self.z := 1 - a1 - a2; end; var f: TVec3f; begin f := TVec3f.Create (0.0, 0.0, 0.0); // <-- error here end. I get the error: project1.lpr(35,37) Error: Wrong number of parameters specified for call to "Create" project1.lpr(25,30) Error: Found declaration: constructor Create(Double;Double); So, obviously, FPC tries to apply the helper of TSomething (which should be decoupled from TVec3f because of the "type TVec3f" declaration) to TVec3f which hasn't defined any constructor with 2 parameters. Is this intended behavior or should I report it as a bug? Versions used: Lazarus 2.3.0 (rev main-2_3-3525-g9208f17734) FPC 3.3.1 i386-win32-win32/win64 (FPC is not the most recent build, it's about 2~3 weeks old) ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] StrIComp
Just a very minor question: Is it intentional that StrIComp (from the strings unit) gives an access violation if one of its arguments is NIL? I hardly work with PChars so this is a serious question from me. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] How to use StrToDateTime() to convert a string with no delimiters?
I always use ScanDateTime for such purposes: https://www.freepascal.org/docs-html/rtl/dateutils/scandatetime.html You can explicitly define the pattern. - Original Message - From: Bo Berglund via fpc-pascal To: fpc-pascal@lists.freepascal.org Sent: Monday, April 24, 2023, 20:08:01 Subject: [fpc-pascal] How to use StrToDateTime() to convert a string with no delimiters? I have a device that sends data over the serial port with a timestamp in this format: (230424194642W) This is coded as yymmddhhnnss and the last char designates daylight savings (S)ummer or normal (W)inter time. In the example above it is W for normal winter time. What I have done so far is: - Remove the () at start and end - Remove the W at the end - Add 20 (as the century) up front - Insert a space after the 6th char (so between date and time - Set the TFormatsettings like this (to say that there are no separators): FS.DateSeparator := #0; (Is this how it is done?) FS.TimeSeparator := #0; - Then the call: Value := StrToDateTime(sValue, FS); (Value is declared as TDateTime) This triggers an exception with the message: "194522" is not a valid time What is the proper way to decode a string as shown above? Since the date part could be decoded, why not also the time part, after all I separated the two with a space and set the same separators? -- Bo Berglund Developer in Sweden ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] DateUtils: (Try)ModifiedJulianDateToDateTime not implemented
Hello, I have seen that the functions for dealing with modified Julian dates are documented as "not yet implemented". Is there a particular reason for that? If not, I'd make an implementation and post it on Gitlab. Kind regards, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Converting old pascal written for Pascal/MT+ compiler
Didn't know that either: "It should be stressed that typed constants are automatically initialized at program start. This is also true for local typed constants and initialized variables. Local typed constants are also initialized at program start. If their value was changed during previous invocations of the function, they will retain their changed value, i. e. they are not initialized each time the function is invoked." described here: https://www.freepascal.org/docs-html/current/ref/refse10.html#x22-210002.2 - Original Message - From: Travis Siegel via fpc-pascal To: FPC-Pascal users discussions Sent: Tuesday, April 4, 2023, 20:34:10 Subject: [fpc-pascal] Converting old pascal written for Pascal/MT+ compiler I'm not positive, because I've never used them, but I'm pretty sure variables configured as const, can't be changed once they're defined. If that's your intent, then feel free to use them, but it sounds like you're trying to make variables (not constant values) last for the whole program, with manipulation being allowed. In that, case, simply define them in the var section before you do any of the functions and procedures. That will make them visible for the whole program, and they won't go out of scope. I know many folks contend that global variables should be kept to a minimum, and scope should be carefully evaluated, and only allow variables to be usable when they're actually needed, and to some degree, I agree, but there's times when it's just too darned convenient to have something accessible for the whole program over multiple functions/procedures, and in those cases, I see nothing wrong with having as many globals as you need. Often, when I'm doing a quick and dirty program, (I.E. one to change a data file from one format to another), I won't even bother with functions and procedures, just write the whole program as one big main procedure, since it's only being run once or twice, then never used again, I see nothing wrong with this approach either, and in that case, all variables are global. No reason you can't do the same, and not depend on quirks of the compiler to keep your items in scope especially when they clearly shouldn't be. Am 04.04.2023 um 08:16 schrieb Jacob Kroon via fpc-pascal: >> I was able to write a couple of perl-scripts that are able to convert >> my old Pascal sources to something that fpc can parse. Amongst other >> things, the scripts inject the "public name"/"external name" >> annotations so that the program can link. >> But I suspect I have a new problem: With the old Pascal/MT+ compiler >> it would appear that local variables declared in functions/procedures >> have a life-time that spans the whole program, like a "static" >> declared variable in C. With fpc, it looks like locally declared >> variables are automatic, put on the stack(?), and so they go out of >> existence once out of scope ? >> The program depends on this feature in the old compiler. I did some >> googling and found that putting local variables in a "const" section >> instead of "var" would make them have a "whole-program" lifetime, but >> then I need to provide them with an initial value. >> Do I have any other option besides changing from "var" to "const" >> everywhere, and provide initial values in all declarations ? >> Regards >> Jacob ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Converting Delphi7 code to FreePascal with interfacing to protection key?
There will surely be better responses than mine, but imho there is an inconsistency in your code: Near/Far calls are a relict of the 16-bit DOS/Win3.x era. The {$F+} switch should be completely obsolete for both Win32 and Win64 executables. .obj files are compiled code (pieces) which are not yet linked together. I cannot imagine that there is a chance to convert a 32-bit .obj file into a .64-bit .obj file without recompilation (i.e. having the sources). So I'd assume that you are stuck to the 32-bit architecture or you might try to obtain a 64-bit .obj from the manufacturer. Maybe he's even released a complete library with a documented API in the meantime? (Even though the hardware key is old it could still be supported as part of the driver series of the manufacturer's current hardware.) - Original Message - From: Bo Berglund via fpc-pascal To: fpc-pascal@lists.freepascal.org Sent: Tuesday, March 21, 2023, 23:49:30 Subject: [fpc-pascal] Converting Delphi7 code to FreePascal with interfacing to protection key? We have a number of old Delphi7 applications which are in need of porting over to FreePascal. I have successfully done a number of these ports in the last few years... But now I am up against a bit of a problem regarding software we have protected using an USB connected hardware key originally bought from Rainbow, a company that has been bought up in several steps and is now named THALES. Anyway, our software interfaces to the SuperPro protection keys is via a Windows driver from THALES and they have provided a software integration kit way back when we started using the keys. It consist of a Delphi unit basically containing a list of definitions of available API functions into the driver looking like this: -- { Force FAR calls } {$F+} INTERFACE CONST { SuperPro API error codes } SP_SUCCESS = 0; SPRO_MAX_QUERY_SIZE= 56; TYPE RB_SPRO_APIPACKET = ARRAY [1..1028] OF CHAR; { Spro API Packet } RB_SPRO_APIPACKET_PTR = ^RB_SPRO_APIPACKET; FUNCTION SproInitialize( ApiPacket : RB_SPRO_APIPACKET_PTR ) : WORD; FUNCTION SproGetExtendedStatus( ApiPacket : RB_SPRO_APIPACKET_PTR ) : WORD; IMPLEMENTATION USES Windows; {$L SPROMEPS.OBJ} { LINK WITH THE SUPERPRO OBJECT FILE } { External functions } FUNCTION RNBOsproFormatPacket( ApiPacket : RB_SPRO_APIPACKET_PTR; thePacketSize : WORD ) : WORD; STDCALL; EXTERNAL; FUNCTION RNBOsproInitialize( ApiPacket : RB_SPRO_APIPACKET_PTR ) : WORD; STDCALL; EXTERNAL; FUNCTION SproInitialize( ApiPacket : RB_SPRO_APIPACKET_PTR ) : WORD; VAR returnVal : WORD; BEGIN returnVal := RNBOsproFormatPacket (ApiPacket, RB_SPRO_APIPACKET_SIZE); IF returnVal <> SP_SUCCESS THEN SproInitialize := returnVal ELSE SproInitialize := RNBOsproInitialize (ApiPacket); END; { SproInitialize } BEGIN END. -- Obviously being from the time when it was received the OBJ file SPROMEPS.OBJ to be linked in is a 32 bit type, so the ported programs need to be compiled/linked into a 32 bit exe file on Windows. Questions: -- 1) How should I go about translating the above to current FreePascal syntax? This involves: { Force FAR calls } {$F+} {$L SPROMEPS.OBJ} { LINK WITH THE SUPERPRO OBJECT FILE } 2) Is there a way to translate/convert the 32 bit Windows SPROMEPS.OBJ file into a 64 bit one such that it could be used for a 64 bit fpc compiler? It is the interface to the protection key driver on the Windows system... It does work for our 32 bit Delphi7 programs on Windows 10 x64, so there must be some 32<->64 bit handling in Windows maybe? -- Bo Berglund Developer in Sweden ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Working with anonymous functions
Dear all, I'm testing FPC-trunk and I'm especially interested in using anonymous functions because they should simplify working with TThread.Synchronize and others a lot. I stumbled upon an issue which I'd like to post here first because I am not sure whether it's a bug or just a wrong usage on my side. Here's a small example: program project1; {$modeswitch anonymousfunctions} {$modeswitch functionreferences} uses Classes, EventLog, SysUtils; type TTest = class FOnLog: TLogMessageEvent; procedure CallOnLog (AEventType: TEventType; AMessage: String); end; procedure TTest.CallOnLog (AEventType: TEventType; AMessage: String); var r: reference to TThreadMethod = nil; m: TThreadMethod = nil; begin // This doesn't work because the anonymous procedure is // capturing local symbols. I understand that this doesn't work. m := procedure begin FOnLog (Self, AEventType, AMessage); end; // As far as I have understood // https://forum.lazarus.freepascal.org/index.php/topic,59468.0.html // the solution should be to use a "reference to". // In fact, assignment works as expected: r := procedure begin FOnLog (Self, AEventType, AMessage); end; // But I seem not to have any change to pass the reference. // Both versions fail: TThread.ForceQueue (NIL, r()); TThread.ForceQueue (NIL, @r); end; begin end. As you can see, the goal is to call TThread.ForceQueue. Of course, the easiest solution was having an overloaded "TThread.ForceQueue (TThread, TThreadProcedure)" as is the case with Delphi. I have already posted a feature request on Github. But I don't know why I can't use a "reference to TThreadMethod". If I understand the feature announcement correctly, this should work, shouldn't it? Kind regards, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Strange floating-point result
Understood, ok. Thanks for your explanation. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Strange floating-point result
Hello, by chance, I stumbled upon a strange behavior in floating-point calculation. Here's the example: program Project1; var f: double; n: integer = 1758; m: integer = 0; begin f := n * 1.2E6 + (2*m+1) * 50E3; // 2109650048 f := Double(n) * 1.2E6 + Double(2*m+1) * 50E3; // 210965 end. Why do I have to explicitly cast Integer to Double here? I never did that before and am a bit worried whether I could get wrong results elsewhere, too, without having them noticed yet. And how does the first value come about? FPC is 3.2.2 on Win64, targeting Win64. Kind regards, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] How to assign overloaded event handler?
I don't know whether this is actually a bug or not but I cannot find a hint in the documentation. It seems that methods assigned to an event handler are not allowed to be overloaded. Or, to be more precise, FPC always uses the first declaration regardless whether it fits or not. Example: program Project1; uses Classes; type TTest = class(TObject) procedure SomeEvent (Sender: NativeInt); overload; procedure SomeEvent (Sender: TObject); overload; end; procedure TTest.SomeEvent (Sender: TObject); begin end; procedure TTest.SomeEvent (Sender: NativeInt); begin end; var x: TTest; y: TStringList; begin x := TTest.Create; y := TStringList.Create; y.OnChange := @x.SomeEvent; end. This doesn't work: project1.lpr(25,17) Error: Incompatible types: got "" expected "" However, when switching both SomeEvent declarations so that the "TObject" variant appears first, it does work. Imho, it should considered a bug because the compiler should be able to detect that there is a matching overloaded method and assign that one. In my simple example, the solution is, of course, to swap declarations. But I'm assigning event handler to a generic class and need event handlers with different types. And it would be helpful if they had the same name when serving the same purpose. Is there a possibility to tell FPC to use a particular method in the assignment? Something like "OnChange:=@(TNotifyEvent(SomeEvent))"? Kind regards, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Get highest element of a StringList
If you just don't like the "-1" for readability, you might also wan't to consider using for i := 0 to Pred(f.Count) do ... - Original Message - From: Thomas Kurz via fpc-pascal To: 'FPC-Pascal users discussions' Sent: Saturday, September 10, 2022, 21:37:34 Subject: [fpc-pascal] Get highest element of a StringList Try this (note the "modeswitch"): program Project1; {$modeswitch typehelpers} uses Classes, SysUtils; type TStringListHelper = class helper for TStringList function High: NativeInt; end; function TStringListHelper.High: NativeInt; begin Exit (Self.Count-1); end; var f: TStringList = nil; i: Integer; begin f := TStringList.Create; f.Add ('hallo'); f.Add ('welt'); f.Add ('!'); for i := 0 to f.High do Writeln (f[i]); FreeAndNil (f); end. - Original Message - From: James Richters via fpc-pascal To: 'FPC-Pascal users discussions' Sent: Saturday, September 10, 2022, 19:57:51 Subject: [fpc-pascal] Get highest element of a StringList This Helper sounds like a nice way to do it. I need the numerical index of the loop so this would be more straight forward. Would I then do something like : For I:= 0 to MyStringList.High Do ? When I try to add the Type statement: type TStringListHelper = class helper for TStringList function High: NativeInt; end; I getError: Identifier not found "class" I have the Classes unit. Is there something else I am missing? James >Another alternative would be declaring a helper: >type TStringListHelper = class helper for TStringList function High: NativeInt; end; >function TStringListHelper.High: NativeInt; begin > Exit (Self.Count-1); >end; ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Get highest element of a StringList
Try this (note the "modeswitch"): program Project1; {$modeswitch typehelpers} uses Classes, SysUtils; type TStringListHelper = class helper for TStringList function High: NativeInt; end; function TStringListHelper.High: NativeInt; begin Exit (Self.Count-1); end; var f: TStringList = nil; i: Integer; begin f := TStringList.Create; f.Add ('hallo'); f.Add ('welt'); f.Add ('!'); for i := 0 to f.High do Writeln (f[i]); FreeAndNil (f); end. - Original Message - From: James Richters via fpc-pascal To: 'FPC-Pascal users discussions' Sent: Saturday, September 10, 2022, 19:57:51 Subject: [fpc-pascal] Get highest element of a StringList This Helper sounds like a nice way to do it. I need the numerical index of the loop so this would be more straight forward. Would I then do something like : For I:= 0 to MyStringList.High Do ? When I try to add the Type statement: type TStringListHelper = class helper for TStringList function High: NativeInt; end; I getError: Identifier not found "class" I have the Classes unit. Is there something else I am missing? James >Another alternative would be declaring a helper: >type TStringListHelper = class helper for TStringList function High: NativeInt; end; >function TStringListHelper.High: NativeInt; begin > Exit (Self.Count-1); >end; ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Get highest element of a StringList
Another alternative would be declaring a helper: type TStringListHelper = class helper for TStringList function High: NativeInt; end; function TStringListHelper.High: NativeInt; begin Exit (Self.Count-1); end; - Original Message - From: James Richters via fpc-pascal To: 'FPC-Pascal users discussions' Sent: Saturday, September 10, 2022, 18:01:20 Subject: [fpc-pascal] Get highest element of a StringList I thought I would try: For Loop := 0 to High(MyStringList) do But I get "Error: Type mismatch" Is there a way to get the highest element of a stringlist other than: For Loop := 0 to MyStringList.Count-1 do It would be nice to not have the -1 Could High() be made to work if the argument was a stringlist? James ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Teaching Kids Using Free Pascal
I currently have only a few missing symbols, mostly math related: Hint: (11030) Start of reading config file P:\Lazarus\fpc\3.2.2\bin\x86_64-win64\fpc.cfg Hint: (11031) End of reading config file P:\Lazarus\fpc\3.2.2\bin\x86_64-win64\fpc.cfg Warning: (11018) You are using the obsolete switch -St Hint: (11030) Start of reading config file X:\Settings\Lazarus\fpcext.cfg Hint: (11031) End of reading config file X:\Settings\Lazarus\fpcext.cfg Free Pascal Compiler version 3.2.2 [2022/01/02] for x86_64 Copyright (c) 1993-2021 by Florian Klaempfl and others (1002) Target OS: Win64 for x64 (3104) Compiling project1.lpr (9015) Linking Z:\project1.exe Z:\project1.lpr(11,1) Error: Undefined symbol: sin Z:\project1.lpr(11,1) Error: Undefined symbol: cos Z:\project1.lpr(11,1) Error: Undefined symbol: __imp___acrt_iob_func Z:\project1.lpr(11,1) Error: Undefined symbol: sqrt Z:\project1.lpr(11,1) Error: Undefined symbol: pow Z:\project1.lpr(11,1) Error: Undefined symbol: floor Z:\project1.lpr(11,1) Fatal: (10026) There were 6 errors compiling module, stopping Fatal: (1018) Compilation aborted Error: P:\Lazarus\fpc\3.2.2\bin\x86_64-win64\ppcx64.exe returned an error exitcode The most tricky one seens to be "__imp___acrt_iob_func". A google search indicated that this one apparently is "hard-coded into the Go linker". So my questions are: - Has libchipmunk-win.a been compiled with Go? (I know that in your original message, you wrote about C, but I just want to be sure.) - Have you tried using the Go linker instead of FPCs one? But I will stay with it. - Original Message - From: Michael Van Canneyt via fpc-pascal To: Anthony Walter via fpc-pascal Sent: Saturday, August 27, 2022, 11:14:55 Subject: [fpc-pascal] Teaching Kids Using Free Pascal On Sat, 27 Aug 2022, Anthony Walter via fpc-pascal wrote: > Some of you might not be aware, but I teach small groups of kids ages 8-16 > computer programming and digital electronics. When teaching programming I > often use Free Pascal and Lazarus, and try to come up with exciting ideas. > Over the past few weeks, I've taught my high school kids who have completed > Algebra I programming using Linear Algebra. To help illustrate vectors, > and matrices, I wrote a small program using Free Pascal to help them > understand the sin(a) function. > I thought I'd share the result: > https://streamable.com/b5ojtt A nice result, thank you for sharing this. I talked to the chairman of the Free Pascal & Lazarus foundation and showed your mail. The subject of teaching kids how to program in Pascal and in particular using it for math problems is something that is close to his heart (and to mine, as this is exactly how I rolled into Free Pascal a quarter of a century ago). He is also the editor of the Blaise Pascal magazine, and has published a book by a dutch author that combines exactly these subjects: https://www.blaisepascalmagazine.eu/product/books-computer-graphics-math-games-download-pdf/ I explained him your problem, and he agreed that the foundation should assist in trying to solve this problem. Therefore, for all: If someone presents a solution that can be distributed with the compiler & FPC which solves or considerably eases the problem (for instance a glue unit that can be included to provide most of the missing symbols, some compiler routines that aid...), the foundation will add another $200 to the bounty offered by Anthony Walter, subject to his and our approval. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Operator not overloaded
Thank you very much, declaring the operator within the record does indeed solve the issue. Just to be sure in case I might need it some day: Does this mean, if I need e.g. a comparison operator for a specialized TPair, I would declare a record class helper and define the operator there? - Original Message - From: Sven Barth via fpc-pascal To: FPC-Pascal users discussions Sent: Friday, June 24, 2022, 10:43:55 Subject: [fpc-pascal] Operator not overloaded Thomas Kurz via fpc-pascal schrieb am Do., 23. Juni 2022, 19:45: > When compiling, I get this error: > pathfinding.pas(17,17) Error: Operator is not overloaded: "TTileSegment" = > "TTileSegment" > Which I don't understand -- because the "=" operator is defined in > tesstypes.pas. > Am I doing something wrong or is this behavior a bug? Global operator overloads need to be available at the time the generic is *declared*, not *specialized*. That is one of the reasons why advanced records were introduced. So you need to declare your operators as part of your record. Regards, Sven ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Operator not overloaded
Hello, I have tried to create an example as minimalistic as possible. I have three files: *** file: pathfinding.pas *** unit PathFinding; {$mode objfpc} interface type generic TAStar = class (TObject) public function FindPath (const AStart: T; const ADestination: T): Boolean; virtual; end; implementation function TAStar.FindPath (const AStart: T; const ADestination: T): Boolean; var current: T; begin current:=Default(T); if (current = ADestination) then Exit (false); end; end. *** file: testtypes.pas *** unit testTypes; {$mode objfpc} interface type TTileSegment = record A: NativeUInt; B: NativeUInt; end; operator = (ALeft: TTileSegment; ARight: TTileSegment): Boolean; operator < (ALeft: TTileSegment; ARight: TTileSegment): Boolean; operator > (ALeft: TTileSegment; ARight: TTileSegment): Boolean; implementation operator = (ALeft: TTileSegment; ARight: TTileSegment): Boolean; begin Exit (True); end; operator < (ALeft: TTileSegment; ARight: TTileSegment): Boolean; begin Exit (True); end; operator > (ALeft: TTileSegment; ARight: TTileSegment): Boolean; begin Exit (True); end; end. *** file: project1.lpr *** program project1; {$mode objfpc} uses testtypes, PathFinding; var x: specialize tastar; begin x := specialize tastar.create; end. ** When compiling, I get this error: pathfinding.pas(17,17) Error: Operator is not overloaded: "TTileSegment" = "TTileSegment" Which I don't understand -- because the "=" operator is defined in tesstypes.pas. Am I doing something wrong or is this behavior a bug? Kind regards, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Functions for dealing with floating-point precision
Hello, in my program I have need for checking floating-point precision. I'm internally using floating-points for calculations, but in the end I have to use integer numbers. I cannot use Round() because I have to check for thresholds. I.e. that I wish to accept a value of 1. as being ">=2". As you can see, I cannot use Trunc() either, so I decided to check for the difference in ULPs (unit in the last place). I couldn't find the corresponding functions in the RTL, but I think they should be included. I wrote the functions listed below. I would appreciate if the maintainers of FPC decide to add them to the Math unit. I skipped the functions for the Extended type, but if it's being desired, I can add hand them in later. Kind regards, Thomas *** code: const MAX_ULP_SINGLE = 2.028240960E+31; const MAX_ULP_DOUBLE = 1.9958403095347198E+292; function SingleToLongBits (Argument: Single): UInt32; begin Move (Argument, Result, SizeOf(UInt32)); end; {$ifdef FPC_HAS_TYPE_DOUBLE} function DoubleToLongBits (Argument: Double): UInt64; begin Move (Argument, Result, SizeOf(UInt64)); end; {$endif FPC_HAS_TYPE_DOUBLE} function LongBitsToSingle (Argument: UInt32): Single; begin Move (Argument, Result, SizeOf(Single)); end; {$ifdef FPC_HAS_TYPE_DOUBLE} function LongBitsToDouble (Argument: UInt64): Double; begin Move (Argument, Result, SizeOf(Double)); end; {$endif FPC_HAS_TYPE_DOUBLE} // returns the first floating-point argument with the sign of the second floating-point argument function CopySign (x: Single; y: Single): Single; begin Exit (Abs(x) * Sign(y)); end; {$ifdef FPC_HAS_TYPE_DOUBLE} // returns the first floating-point argument with the sign of the second floating-point argument function CopySign (x: Double; y: Double): Double; begin Exit (Abs(x) * Sign(y)); end; {$endif FPC_HAS_TYPE_DOUBLE} function IsSameSign (x: Single; y: Single): Boolean; begin Exit (CopySign(x, y) = x); end; {$ifdef FPC_HAS_TYPE_DOUBLE} function IsSameSign (x: Double; y: Double): Boolean; begin Exit (CopySign(x, y) = x); end; {$endif FPC_HAS_TYPE_DOUBLE} function NextAfter (Start: Single; Direction: Single): Single; var absStart: Single; absDir: Single; toZero: Boolean; begin // If either argument is a NaN, then NaN is returned. if IsNan(Start) OR IsNan(Direction) then Exit (NaN); // If both arguments compare as equal the second argument is returned. if (Start = Direction) THEN Exit (Direction); absStart := Abs(Start); absDir := Abs(Direction); toZero := NOT IsSameSign (Start, Direction) OR (AbsDir < absStart); if (toZero) then begin // we are reducing the magnitude, going toward zero. if (absStart = MinSingle) then Exit (CopySign (0.0, Start)); if IsInfinite(absStart) THEN Exit (CopySign (MaxSingle, Start)); Exit (CopySign (LongBitsToSingle (Pred(SingleToLongBits(absStart))), Start)); end else begin // we are increasing the magnitude, toward +-Infinity if (Start = 0.0) then Exit (CopySign (MinSingle, Direction)); if (absStart = MaxSingle) then Exit (CopySign (Infinity, Start)); Exit (CopySign (LongBitsToSingle(Succ(SingleToLongBits(absStart))), Start)); end; end; {$ifdef FPC_HAS_TYPE_DOUBLE} function NextAfter (Start: Double; Direction: Double): Double; var absStart: Double; absDir: Double; toZero: Boolean; begin // If either argument is a NaN, then NaN is returned. if IsNan(Start) OR IsNan(Direction) then Exit (NaN); // If both arguments compare as equal the second argument is returned. if (Start = Direction) THEN Exit (Direction); absStart := Abs(Start); absDir := Abs(Direction); toZero := NOT IsSameSign (Start, Direction) OR (AbsDir < AbsStart); if (toZero) then begin // we are reducing the magnitude, going toward zero. if (absStart = MinDouble) then Exit (CopySign (0.0, Start)); if IsInfinite(absStart) THEN Exit (CopySign (MaxDouble, Start)); Exit (CopySign (LongBitsToDouble (Pred(DoubleToLongBits(absStart))), Start)); end else begin // we are increasing the magnitude, toward +-Infinity if (Start = 0.0) then Exit (CopySign (MinDouble, Direction)); if (AbsStart = MaxDouble) then Exit (CopySign (Infinity, Start)); Exit (CopySign (LongBitsToDouble(Succ(DoubleToLongBits(absStart))), start)); end; end; {$endif FPC_HAS_TYPE_DOUBLE} function FloatPrior (Argument: Single): Single; begin Exit (NextAfter (Argument, NegInfinity)); end; function FloatNext (Argument: Single): Single; begin Exit (NextAfter (Argument, Infinity)); end; {$ifdef FPC_HAS_TYPE_DOUBLE} function FloatPrior (Argument: Double): Double; begin Exit (NextAfter (Argument, NegInfinity)); end; {$endif FPC_HAS_TYPE_DOUBLE} {$ifdef FPC_HAS_TYPE_DOUBLE} function FloatNext (Argument: Double): Double; begin Exit (NextAfter (Argument, Infinity)); en
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
This is horrendous code, especially the last example. Looks like PHP or JavaScript, which I hate because their code is hard to read. I'm using pascal because I like its clean and easy-to-read syntax. "-1" is a statement that should give a compiler error. "Result" and "Exit(x)" are established constructs and I don't see any need for changing, or even worse: omitting, them. What should the data type of "left, right" be? What should "@" mean? - Original Message - From: Benito van der Zander via fpc-pascal To: fpc-pascal@lists.freepascal.org Sent: Saturday, May 28, 2022, 14:04:46 Subject: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions Hi, > Sort((left, right) begin > if left < right then >result := -1 > else if left > right then >result := 1 > else >result := 0; >end); One could introduce the @ operator to get a reference to a block of code. Sort( @(left, right) begin if left < right then result := -1 else if left > right then result := 1 else result := 0; end); The "result" variable is also ugly. You could make "if" an expression: Sort( @(left, right) begin result := if left < right then -1 else if left > right then 1 else 0; end); Then the begin end could be removed too. Make @:= an operator to turn an expression to a function Sort( @(left, right) := if left < right then -1 else if left > right then 1 else 0; ); Benito ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
Great!!! Thank you very very much :))) - Original Message - From: Sven Barth via fpc-pascal To: fpc-annou...@lists.freepascal.org Sent: Thursday, May 26, 2022, 21:47:06 Subject: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions Dear Free Pascal Community, The Free Pascal Developer team is pleased to finally announce the addition of a long awaited feature, though to be precise it's two different, but very much related features: Function References and Anonymous Functions. These two features can be used independantly of each other, but their greatest power they unfold when used together. These features are based on the work by Blaise.ru, so thank you very much and I hope you're doing well considering the current situation. In the following we'll highlight both features separately and then we'll take a look at using them together. = Function References = Function References (also applicable names are Procedure References and Routine References, in the following only Function References will be used) are types that can take a function (or procedure or routine), method, function variable (or procedure variable or routine variable), method variable, nested function (or nested procedure or nested routine) or an anonymous function (or anonymous procedure or anonymous routine) as a value. The function reference can then be used to call the provided function just like other similar routine pointer types. In contrast to these other types nearly all function-like constructs can be assigned to it (the only exception are nested function variables (or nested procedure variables or nested routine variables), more about that later on) and then used or stored. Function references are enabled with the modeswitch FUNCTIONREFERENCES (the following examples will assume that this modeswitch is provided). A function reference is declared as follows: REFERENCE TO FUNCTION|PROCEDURE [(argumentlist)][: resulttype;] [directives;] Examples: === code begin === type TProcLongInt = reference to procedure(aArg: LongInt); stdcall; TFuncTObject = reference to function(aArg: TObject): TObject; === code end === Like other function pointer types function references can also be declared as generic: === code begin === type generic TGenericProc = reference to procedure(aArg: T); === code end === As you can see, once function references are enabled you can't use the identifier "REFERENCE" as part of an alias declaration without using "&": === code begin === type someref = reference; // will fail someref = &reference; // correct fix var somevar: reference; // will fail somevar: &reference; // correct fix === code end === A function reference variable can then be called like any other function pointer type: === code begin === var p: TProcLongInt; begin p := @SomeLongIntProc; p(42); end. === code end === If a function reference has no parameters then you need to use "()" nevertheless in the FPC/ObjFPC modes like for other function pointer types: === code begin === type TProc = reference to procedure; var p: TProc; begin p := @SomeProcedure; p(); // required p; // this can be used e.g. in mode Delphi end. === code end === Like other function pointer types they can also be declared anonymously as part of a variable, field declaration (but not as part of a paramater declaration): === code begin === var f: reference to function: LongInt; type TTest = class f: reference to procedure; end; === code end === They get their great power from a point that is for once *not* considered an implementation detail: function references are in fact internally declared as reference counted interfaces with a single Invoke() method of the provided signature. So the above examples are in fact declared like this: === code begin === type TProcLongInt = interface(IInterface) procedure Invoke(aArg: LongInt); stdcall; overload; end; TFuncTObject = interface(IInterface) procedure Invoke(aArg: TObject): TObject; overload; end; generic TGenericProc = interface(IInterface) procedure Invoke(aArg: T); overload; end; === code end === This has a few implications: - in the RTTI this will appear like a normal interface - it reacts to the $M directive like a normal interface - it is a managed type - it has *no* valid GUID - it can be implemented by a class - it can be inherited from Especially the last two points are important. That the interface can be implemented means that much more functionality and state can be added to a function reference: === code begin === type TFunc = reference to function: LongInt; TSomeImpl = class(TInterfacedObject, TFunc) f: LongInt; function Invoke: LongInt; end; function TSomeImpl.Invoke: LongInt; begin Result := f; end; var t: TSomeImpl; f: TFunc; begin t := TSomeImpl.Create; f := t; Writeln(f()); // will wri
[fpc-pascal] Strange "division by zero" error using variants
Dear all, please consider the following code: program Project1; {$booleval off} var v1, v2: variant; a: boolean; b: integer; begin a := true; b := 0; // this works as expected: if a and (b > 0) and ((0+1) mod b = 0) then Writeln ('ok'); v1 := true; v2 := 0; // this gives a "division by zero": if v1 and (v2 > 0) and ((0+1) mod v2 = 0) then Writeln ('ok'); end. The "variant" variant results in a "division by zero". Obviously, it tries to evaluate the modulo-expression even though this shouldn't happen because complete boolean evaluation is disabled and the "if"-result is already known to be false after checking "v2>0". Can anyone explain this strange behavior? Kind regards, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Correct way for using TThread.ForceQueue?
EDIT: The code should be "TThread.ForceQueue", not "TThread.Synchronize"; I have corrected that. I cannot remember why, but a long time ago when learning Delphi 5 or 6, I have learned not to call the destructor from within any method of the class, only from outside. If this is no longer true nowadays (or maybe, has never been true before), I'd like to use this solution. Just to be sure we're talking about the same thing -- you think this code should work: type TMyData = class method: TMethodWithParameters; a: whatever; procedure Run; end; procedure TMyData.Run; begin method (a); Self.Free; end; ... MyData := TMyData.Create; MyData.a := ...; MyData.method := @SomeMethodWithParameters; TThread.ForceQueue (NIL, @MyData.Run) - Original Message - From: Michael Van Canneyt via fpc-pascal To: Thomas Kurz via fpc-pascal Sent: Monday, April 25, 2022, 16:58:26 Subject: [fpc-pascal] Correct way for using TThread.ForceQueue? On Mon, 25 Apr 2022, Thomas Kurz via fpc-pascal wrote: > This is a very elegant solution but it can only be used for Synchronize, > right? Because with ForceQueue I cannot know when it's done and freeing > within Run (i.e. "Self.Free") would fail. Why would this fail according to you ? I have used this approach on multiple occasions. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Correct way for using TThread.ForceQueue?
I cannot remember why, but a long time ago when learning Delphi 5 or 6, I have learned not to call the destructor from within any method of the class, only from outside. If this is no longer true nowadays (or maybe, has never been true before), I'd like to use this solution. Just to be sure we're talking about the same thing -- you think this code should work: type TMyData = class method: TMethodWithParameters; a: whatever; procedure Run; end; procedure TMyData.Run; begin method (a); Self.Free; end; ... MyData := TMyData.Create; MyData.a := ...; MyData.method := @SomeMethodWithParameters; TThread.Synchronize(NIL, @MyData.Run) - Original Message - From: Michael Van Canneyt via fpc-pascal To: Thomas Kurz via fpc-pascal Sent: Monday, April 25, 2022, 16:58:26 Subject: [fpc-pascal] Correct way for using TThread.ForceQueue? On Mon, 25 Apr 2022, Thomas Kurz via fpc-pascal wrote: > This is a very elegant solution but it can only be used for Synchronize, > right? Because with ForceQueue I cannot know when it's done and freeing > within Run (i.e. "Self.Free") would fail. Why would this fail according to you ? I have used this approach on multiple occasions. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Correct way for using TThread.ForceQueue?
This is a very elegant solution but it can only be used for Synchronize, right? Because with ForceQueue I cannot know when it's done and freeing within Run (i.e. "Self.Free") would fail. Using an advanced record would be fine, but it doesn't fit the declaration "TThreadMethod = procedure of object". - Original Message - From: Mattias Gaertner via fpc-pascal To: fpc-pascal@lists.freepascal.org Sent: Monday, April 25, 2022, 16:12:40 Subject: [fpc-pascal] Correct way for using TThread.ForceQueue? On Mon, 25 Apr 2022 15:47:57 +0200 Thomas Kurz via fpc-pascal wrote: >[...] > As far as I have seen so far, the common solution is to use a > variable inside the class to cache the parameters, then to use a > DoCallSync procedure which takes no parameters but can use the cached > values inside, and finally to call TThread.Synchronize(NIL, > @DoCallSync). I have stick to this concept when using Synchronize, > too. Or some small class: type TMyData = class a: whatever; procedure Run; end; MyData:=TMyData.Create; MyData.a:=...; TThread.Synchronize(NIL, @MyData.Run). Free MyData when done and/or in the destructor. >[...] Mattias ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Correct way for using TThread.ForceQueue?
Hello, my question is about using the TThread.Synchronize, Queue and ForceQueue methods. Unfortunately, the parameter they take is of type TThreadMethods which allows calling only methods having no parameters at all. I assume this is done to simplify the implementation on client-side but causes headaches on my side :) Delphi solves the issue with having anonymous methods which aren't yet available in FPC yet. So unfortunately I cannot do something like TThread.Synchronize(NIL, @procedure(a,b,c)). As far as I have seen so far, the common solution is to use a variable inside the class to cache the parameters, then to use a DoCallSync procedure which takes no parameters but can use the cached values inside, and finally to call TThread.Synchronize(NIL, @DoCallSync). I have stick to this concept when using Synchronize, too. But what is the correct way to deal with ForceQueue? I think I cannot use a global variable for this case because its value could be overwritten between the call to ForceQueue and the moment the queued method is actually being run. Do I have to use a FIFO-buffer for this purpose? And if yes, would it be safe (in the sense of getting no deadlock situations) to use a TThreadList for that? Kind regards, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Possible fpdebug issue
Dear all, I'm not sure whether or not this is an issue with fpdebug, so I'd like to describe it here first: I have a main program (Win32 GUI running on Win 8.1) which loads and unloads a DLL dynamically. I know that fpdebug is currently not able to debug DLLs, but imho I don't do so, but the issue might be related. The program runs fine when being run without debugger or when using GDB. However, a crash occurs when fpdebug is active and the call to "FreeLibrary" is made. The error is: Project raised exception class 'External: Unknown exception code $E0465043'. At address 76EB56E8. The DLL is my own and I tried to debug the Finalization section with GDB, but I cannot find an issue there. So imho unloading the DLL should not cause any trouble. As I said, I'm not trying to actually step into the DLL; I'm only using fpdebug in the main program and trying to step over the "FreeLibrary" line. Kind regards, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature announcement: implicit generic function specializations
Thank you for continuously enhancing Free Pascal. Happy to see every new feature :) Is there any work ongoing about overloaded properties? E.g. property x: integer read GetX; property x[aindex: integer]: integer write SetX; I know that declaring the property only once and overloading the getters and setters work, but sometimes I wish to have different read/readwrite/write access for overloaded properties and this is not possible at the moment. Furthermore, code completion in Lazarus doesn't show the different parameters of overloaded properties. - Original Message - From: Sven Barth via fpc-pascal To: fpc-annou...@lists.freepascal.org Sent: Wednesday, April 20, 2022, 19:15:15 Subject: [fpc-pascal] Feature announcement: implicit generic function specializations Dear FPC community, The FPC developers are pleased to announce the implementation of a new feature: implicit generic function specializations. This feature was implemented by Ryan Joseph, so thank you very much, Ryan. This feature allows you to use generic routines (functions, procedures, methods) without explicitely specializing them (“<…>” in Delphi modes and “specialize …<…>” in non-Delphi modes) as long as the compiler can determine the correct parameter types for the generic. This feature is enabled with the modeswitch ImplicitFunctionSpecialization and is for now not enabled by default as this has the potential to break existing code. Assume you have the following function: === code begin === generic function Add(aArg1, aArg2: T): T; begin Result := aArg1 + aArg2; end; === code end === Up to now you could only use this function as follows: === code begin === SomeStr := specialize Add('Hello', 'World'); SomeInt := specialize Add(2, 5); === code end === However with implicit function specializations enabled you can also use it as follows: === code begin === SomeStr := Add('Hello', 'World'); SomeInt := Add(2, 5); === code end === The compiler will automatically determine the type of the generic parameters based on the parameters you pass in (this is always done left to right). Depending on the passed in parameters (especially if you're using constant values like in the example instead of variables) the compiler might however pick a different type than you expected. You can enforce a specific type by either explicitely specializing the method as before or by inserting a type cast. In the example above the compile will specialize the call with the parameters “2, 5” using an 8-bit signed type (Pascal prefers signed types) instead of a LongInt as in the explicit specialization. If you use “LongInt(2), 5” as parameters then the compiler will pick that instead, however with “2, LongInt(5)” it will still pick an 8-bit type, because the parameter types are determined left to right. If there exists a non-generic overload for which the parameters types match exactly, the compiler will pick that instead of specializing something anew. So assume you also have the following function in scope: === code begin === function Add(aArg1, aArg2: LongInt): LongInt; begin Result := aArg1 + aArg2; end; === code end === In the case of “Add(2, 5)” the compiler will *not* pick the non-generic function, because it determines that an 8-bit type is enough, however if you use “Add(LongInt(2), 5)” the compiler will pick the non-generic function. Aside from simple parameters the compiler also supports arrays and function/method variables: === code begin === generic function ArrayFunc(aArg: specialize TArray): T; var e: T; begin Result := Default(T); for e in aArg do Result := Result + e; end; type generic TTest = function(aArg: T): T; generic function Apply(aFunc: specialize TTest; aArg: T): T; begin Result := aFunc(aArg); end; function StrFunc(aArg: String): String; begin Result := UpCase(aArg); end; function NegFunc(aArg: LongInt): LongInt; begin Result := - aArg; end; begin Writeln(ArrayFunc([1, 2, 3])); // will write 6 Writeln(ArrayFunc(['Hello', 'FPC', 'World'])); // will write HelloFPCWorld Writeln(Apply(@StrFunc, 'Foobar')); // will write FOOBAR Writeln(Apply(@NegFunc, 42)); // will write -42 end. === code end === There are of course a few restrictions for this feature: - all generic parameters must be used in the declaration of the routine (implementation only type parameters are not allowed) - all parameters that have a generic type must not be default parameters, they need to be used in the call or their type must have been fixed by a parameter further left (as currently default values for parameters of a generic type are not supported this is not much of a restriction, but should that change (e.g. Default(T)) then this restriction will apply) - the generic routine must not have constant generic parameters (this might be extended in the future with e.g. static arrays or file types, but for now this restriction stands) - the result type is
Re: [fpc-pascal] Caller agnostic procedure variables
> The "Reference to procedure" that will be part of anonymous functionswill do > this for you. What release are anonymous functions planed for? FPC 3.4.0? ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Strange behavior in generics.collections TDictionary
Consider the following code: *** PROGRAM project1; {$mode objfpc} {$longstrings on} // see output below {$modeswitch advancedrecords} USES Variants, Generics.Collections, SysUtils; TYPE TRecord = PACKED RECORD FID: NativeUInt; FKey: String; CONSTRUCTOR Create (AID: NativeUInt; AKey: String); END; CONSTRUCTOR TRecord.Create (AID: NativeUInt; AKey: String); BEGIN FID := AID; FKey := UpperCase (AKey); END; VAR Dict: SPECIALIZE TDictionary; i: SPECIALIZE TPair; BEGIN Dict := SPECIALIZE TDictionary.Create; Dict.Add (TRecord.Create (1, 'test'), 1); FOR i IN Dict DO Writeln (i.Key.FID, #9, i.Key.FKey, #9, i.Value); // ^^^ 1 TEST 1 // -> so the entry is ok! Writeln (Dict.ContainsKey (TRecord.Create (1, 'test'))); // ^^^ with longstrings on -> FALSE // with longstrings off -> TRUE Writeln (Dict.ContainsKey (TRecord.Create (1, 'TEST'))); // ^^^ always FALSE Dict.Free; END. *** I'm very confused... I have no idea if I'm overseeing something or this is a bug in generics.collections or in the compiler. My system is: Lazarus 2.2.0 (64 bit), FPC 3.2.2 (64 bit) on Windows 8.1 (64 bit) ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal