Re: [fpc-devel] Implicit function specialization precedence
I found something sneaky I'd like to confirm before I decide what to do about it. 1) "T" in TAnyClass is specialized as Integer from the first parameter with TSomeClass (which is TAnyClass). 2) "U" is getting specialized as String by looking at the parameters in Compare() in which "U"(the second generic parameter) is String. This specializes the procedure correctly but it uses a very sneaky method which is very hard to discern. I feel like that if a generic parameter is already used (like T in specialize TCallback) then no further attempt should be made to look at the parameters and in the example below "U" would not be found and the function would fail to implicitly specialize. == type generic TAnyClass = class type TElem = U; end; type TSomeClass = specialize TAnyClass; type generic TCallback = function(a: T; b: U): integer; function Compare(a: TSomeClass.TElem; b: string): integer; begin result := 1; end; generic procedure DoThis(aClass: specialize TAnyClass; callback: specialize TCallback); begin callback(1, 'string'); end; begin DoThis(TSomeClass.Create, @Compare); end. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
[fpc-devel] Defer keyword
Something which annoys me about Pascal is cleanup in which a function exits in multiple places but there is no formal way to free memory which may be used in the current scope. I say ultimately Pascal needs some opt-in automatic reference counting for TObject but the "defer" keyword would be helpful alternative to what we have now, which is nothing. The concept is very easy to understand and should be easy to implement by simply making a "defer" statement node which is added to a list and then called during function finalization like the other ref counted objects (dynamic array, interfaces etc). I've seen it appear in multiple languages already and it's a sound idea in my opinion. Is this something worth perusing for Pascal? https://www.hackingwithswift.com/example-code/language/how-to-delay-execution-of-code-using-the-defer-keyword https://www.geeksforgeeks.org/defer-keyword-in-golang/ procedure DoStuff; begin obj := TObject.Create; defer objects.Free; while true do begin // don't worry, obj will be freed safely if not obj.TrySomething then exit; end; end; Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Defer keyword
Op 2021-05-06 om 17:38 schreef Ryan Joseph via fpc-devel: Something which annoys me about Pascal is cleanup in which a function exits in multiple places but there is no formal way to free memory which may be used in the current scope. I say ultimately Pascal needs some opt-in automatic reference counting for TObject but the "defer" keyword would be helpful alternative to what we have now, which is nothing. The concept is very easy to understand and should be easy to implement by simply making a "defer" statement node which is added to a list and then called during function finalization like the other ref counted objects (dynamic array, interfaces etc). But those types have refcounting built-in and always active. Things like defer don't, which makes that all objects gets refcounting overhead in case somebody needs it for "defer". Contrary to Pascal both the language you reference have garbage collectors, so their objects are already managed anyway, ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Defer keyword
> On May 6, 2021, at 10:44 AM, Marco van de Voort via fpc-devel > wrote: > > But those types have refcounting built-in and always active. Things like > defer don't, which makes that all objects gets refcounting overhead in case > somebody needs it for "defer". > > Contrary to Pascal both the language you reference have garbage collectors, > so their objects are already managed anyway, The idea of defer isn't necessarily about memory management but rather literally just deferring a statements execution until a predicable point in execution (end of a block or function). Those articles mentioned using them for file IO also so that you can be sure you're going to close the open file handle even if the function returns before. Memory management is just one obvious use case since we have this problem in Pascal often. I don't think this even affects ref counting of existing types because it all it does it move the statement to the end of the block. Maybe I'm not understanding your point though. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Defer keyword
In the example given: obj := TObject.Create; defer objects.Free; What's wrong with Pascal's existing functionality? obj := TObject.Create; try ... finally objects.Free; end; If there's a concern about performance penalty, maybe the compiler can work something out for simple finally blocks and just copy the code to any Exit nodes found rather than calling the pseudo-procedure that a try...finally block creates. Gareth aka. Kit On 06/05/2021 18:11, Ryan Joseph via fpc-devel wrote: On May 6, 2021, at 10:44 AM, Marco van de Voort via fpc-devel wrote: But those types have refcounting built-in and always active. Things like defer don't, which makes that all objects gets refcounting overhead in case somebody needs it for "defer". Contrary to Pascal both the language you reference have garbage collectors, so their objects are already managed anyway, The idea of defer isn't necessarily about memory management but rather literally just deferring a statements execution until a predicable point in execution (end of a block or function). Those articles mentioned using them for file IO also so that you can be sure you're going to close the open file handle even if the function returns before. Memory management is just one obvious use case since we have this problem in Pascal often. I don't think this even affects ref counting of existing types because it all it does it move the statement to the end of the block. Maybe I'm not understanding your point though. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel -- This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Defer keyword
> On May 6, 2021, at 11:39 AM, J. Gareth Moreton via fpc-devel > wrote: > > In the example given: > > obj := TObject.Create; > defer objects.Free; > > What's wrong with Pascal's existing functionality? > > obj := TObject.Create; > try >... > finally >objects.Free; > end; > > If there's a concern about performance penalty, maybe the compiler can work > something out for simple finally blocks and just copy the code to any Exit > nodes found rather than calling the pseudo-procedure that a try...finally > block creates. I didn't know try..finally even worked like that. :) I thought it was just for exceptions but I see it captures exit also. The defer keyword is nicer on the eyes I would say because it don't require wrapping the entire function in a big block of code. So never mind then I guess. I'll start using try..finally and see how that works for me. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Defer keyword
The rule with try...finally is that, outside of something completely catastrophic that destroys the program flow, is that once you enter the try part, the finally part is guaranteed to be executed no matter how you leave it. Gareth aka. Kit On 06/05/2021 18:53, Ryan Joseph via fpc-devel wrote: On May 6, 2021, at 11:39 AM, J. Gareth Moreton via fpc-devel wrote: In the example given: obj := TObject.Create; defer objects.Free; What's wrong with Pascal's existing functionality? obj := TObject.Create; try ... finally objects.Free; end; If there's a concern about performance penalty, maybe the compiler can work something out for simple finally blocks and just copy the code to any Exit nodes found rather than calling the pseudo-procedure that a try...finally block creates. I didn't know try..finally even worked like that. :) I thought it was just for exceptions but I see it captures exit also. The defer keyword is nicer on the eyes I would say because it don't require wrapping the entire function in a big block of code. So never mind then I guess. I'll start using try..finally and see how that works for me. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel -- This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Defer keyword
J. Gareth Moreton via fpc-devel schrieb am Do., 6. Mai 2021, 20:03: > The rule with try...finally is that, outside of something completely > catastrophic that destroys the program flow, is that once you enter the > try part, the finally part is guaranteed to be executed no matter how > you leave it. > There are two exceptions (pun not intended :P ): - Halt (or any other OS function that never returns and terminates the process) - LongJmp (because that knows nothing about exception handlers) Other than that, you're right and what Ryan is trying to do is definitely the intended purpose of try ... finally. Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Defer keyword
> On May 6, 2021, at 4:05 PM, Sven Barth via fpc-devel > wrote: > > Other than that, you're right and what Ryan is trying to do is definitely the > intended purpose of try ... finally. > Is there any runtime code involved with try..finally or does it just reorganize the code to run at the end of the block? My understanding of the defer keyword is that is was just a fancy way to move some code into a block which always gets run with a function exits. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Defer keyword
There is some special handling involved in that the code inside the try part (I think) is effectively a nested procedure. It's important in the context of stack unwinding when an exception occurs. There is a performance penalty when using them, which one reason why the compiler sources don't use them. There's probably other reasons too. There might be some speed-up potential where standard Exit calls are concerned, but I'm not sure. Gareth aka. Kit On 06/05/2021 23:17, Ryan Joseph via fpc-devel wrote: On May 6, 2021, at 4:05 PM, Sven Barth via fpc-devel wrote: Other than that, you're right and what Ryan is trying to do is definitely the intended purpose of try ... finally. Is there any runtime code involved with try..finally or does it just reorganize the code to run at the end of the block? My understanding of the defer keyword is that is was just a fancy way to move some code into a block which always gets run with a function exits. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel -- This email has been checked for viruses by Avast antivirus software. https://www.avast.com/antivirus ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Defer keyword
> On May 6, 2021, at 4:26 PM, J. Gareth Moreton via fpc-devel > wrote: > > There is a performance penalty when using them, which one reason why the > compiler sources don't use them. There's probably other reasons too. There > might be some speed-up potential where standard Exit calls are concerned, but > I'm not sure. I just did a search and I did indeed see a few try..finally blocks but not many. As I understand it there is a "finalization" section of each procedure which is used for ref counted objects so I assumed the statement was merely moved to that location but I guess there's some concerns over exceptions. Either way looking at the programming language landscape the better way forward seems to be some opt-in ARC for TObject but I don't know if the compiler team is receptive to that (Sven made some attempt years ago but abandoned it). it's kind of frustrating that we have ref counted types but that isn't extended to classes. Hopefully that's something we can tackle one of these days... Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Defer keyword
Hi, 07.05.2021 1:32, Ryan Joseph via fpc-devel: [...] it's kind of frustrating that we have ref counted types but that isn't extended to classes. Indeed. However, unfortunately classes are substantially different in that they can cause reference circles, which then cause damage to ref counting, unless some severe complications are implemented, and then it will probably get close to garbage collection. Well, AFAIU. Regards, Nikolai Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
[fpc-devel] (ref types / circles) Re: Defer keyword
On 07/05/2021 01:36, Nikolai Zhubr via fpc-devel wrote: Indeed. However, unfortunately classes are substantially different in that they can cause reference circles, You can already cause ref circles, no classes needed. type TR = record a: array of TR; end; var x: TR; begin SetLength(x.a,99); x.a[0] := x; end. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] (ref types / circles) Re: Defer keyword
Hi Martin, 07.05.2021 2:41, Martin Frb via fpc-devel: On 07/05/2021 01:36, Nikolai Zhubr via fpc-devel wrote: Indeed. However, unfortunately classes are substantially different in that they can cause reference circles, You can already cause ref circles, no classes needed. Yes, records and objects are the same as classes in this respect. You cannot do circles with any other types, AFAIK. Regards, Nikolai type TR = record a: array of TR; end; var x: TR; begin SetLength(x.a,99); x.a[0] := x; end. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] (ref types / circles) Re: Defer keyword
> On May 6, 2021, at 5:41 PM, Martin Frb via fpc-devel > wrote: > > You can already cause ref circles, no classes needed. > > type > TR = record > a: array of TR; > end; > > var > x: TR; > begin > SetLength(x.a,99); > x.a[0] := x; > end. This can be detected at compile and at least give a warning. "a" is a member of TR and the element type of "a" is TR, then we're assigning TR to said array. It's that simple I think. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] (ref types / circles) Re: Defer keyword
> On May 6, 2021, at 7:14 PM, Ryan Joseph wrote: > > This can be detected at compile and at least give a warning. "a" is a member > of TR and the element type of "a" is TR, then we're assigning TR to said > array. It's that simple I think. It also occurs to me that record management operators already allow these types of circular references. It's just par for the course with ref counting and something programmers need to be aware of. Regards, Ryan Joseph ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Defer keyword
Am 07.05.2021 um 00:17 schrieb Ryan Joseph via fpc-devel: On May 6, 2021, at 4:05 PM, Sven Barth via fpc-devel wrote: Other than that, you're right and what Ryan is trying to do is definitely the intended purpose of try ... finally. Is there any runtime code involved with try..finally or does it just reorganize the code to run at the end of the block? My understanding of the defer keyword is that is was just a fancy way to move some code into a block which always gets run with a function exits. It depends on the platform. In general FPC uses setjmp/longjmp based exception handling, thus there is a slight penalty in setting up the exception frame (no matter if "finally" or "except"). In case of Win32 and Win64 the OS' Structured Exception Handling functionality is used. On i386-win32 there is still a runtime overhead due to how exceptions are managed, but on x86_64-win64 and aarch64-win64 (and in theory also arm-wince and arm-win32, but we have no ARM support for SEH yet (and arm-win32 isn't implemented yet :P )) this is done through meta data located in the PE file (the .pdata and .xdata sections) which allows for an implicit setup of the frames and thus there'll only be a penalty if an exception occurrs (cause the OS and the exception handling code will have to parse that data). Trunk also supports POSIX exceptions on selected *nix based systems, though I haven't looked in depth yet in how far they incur a runtime penalty (also they need to be enabled by enabling them in the compiler and then recompiling everything, cause they're still experimental). Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Defer keyword
Am 07.05.2021 um 00:32 schrieb Ryan Joseph via fpc-devel: On May 6, 2021, at 4:26 PM, J. Gareth Moreton via fpc-devel wrote: There is a performance penalty when using them, which one reason why the compiler sources don't use them. There's probably other reasons too. There might be some speed-up potential where standard Exit calls are concerned, but I'm not sure. I just did a search and I did indeed see a few try..finally blocks but not many. As I understand it there is a "finalization" section of each procedure which is used for ref counted objects so I assumed the statement was merely moved to that location but I guess there's some concerns over exceptions. There is no "finalization" section. It's really just an implicit try ... finally block that the compiler inserts. Look for "cs_implicit_exceptions" and "pi_needs_implicit_finally" if you want to learn more. Either way looking at the programming language landscape the better way forward seems to be some opt-in ARC for TObject but I don't know if the compiler team is receptive to that (Sven made some attempt years ago but abandoned it). it's kind of frustrating that we have ref counted types but that isn't extended to classes. Hopefully that's something we can tackle one of these days... The problem is that the whole class tree needs to support it for it to work correctly even if it's not the whole hierarchy that has as it enabled. That means at least one additional field inside TObject that a) controls that behavior and b) contains the reference count. This means that *all* class instances increase by a LongInt. This might not sound like much, but FPC also allows to work on smaller systems (and I don't mean the really small embedded ones as those don't have TObject enabled anyway) and there an additional LongInt for each instance might be critical. If the reference count feature is optional (in addition to the above) then an open question is what would happen if such a reference counted instance is assigned to a non-reference counted one. This would need to take into account all ways such an instance or type can be used including TClass. If the reference count would be enabled by default for *all* instance (like Delphi did in its platform compilers but which they abandoned now) then you'd have a huge backwards compatibility problem, because there definitely are cycles out there and thus this option would be an absolute no-no. In my opinion the better solution is to continue the road that Maciej started and to implement that "default field" concept together with operator hoistening so that records with management operators can be used as containers. This is essentially the way it's done in C++ as well (e.g. we use that extensively at work), but it needs some questions solved for the default field functionality. This way the functionality is definitely optional and can be controlled per-instance instead of per-type. What it wouldn't solve however would be the assignment problems ("wrapped" to non-"wrapped" instance) though that could be probably be more or less solved by only allowing an explicit conversion to the non-"wrapped" instance. Regards, Sven ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
Re: [fpc-devel] Defer keyword
On Fri, 7 May 2021, Sven Barth via fpc-devel wrote: In my opinion the better solution is to continue the road that Maciej started and to implement that "default field" concept together with operator hoistening so that records with management operators can be used as containers. This is essentially the way it's done in C++ as well (e.g. we use that extensively at work), but it needs some questions solved for the default field functionality. This way the functionality is definitely optional and can be controlled per-instance instead of per-type. What it wouldn't solve however would be the assignment problems ("wrapped" to non-"wrapped" instance) though that could be probably be more or less solved by only allowing an explicit conversion to the non-"wrapped" instance. I thought it was agreed at the time that this was the most viable way forward ? IIRC there was also the proposal that this could be done automatically using a keyword: var SomeClass : TSomeClass; dispose; The compiler can internally create the management record with a single default field and the needed management operator, so the user does not need to create all that. I cannot speak for others, but I think 90% of potential use cases for ref counting would be covered like this in my code: objects that only live inside a procedure. Michael. ___ fpc-devel maillist - fpc-devel@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel