Re: [fpc-devel] Implicit function specialization precedence

2021-05-06 Thread Ryan Joseph via fpc-devel
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

2021-05-06 Thread 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).

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

2021-05-06 Thread Marco van de Voort via fpc-devel


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

2021-05-06 Thread Ryan Joseph via fpc-devel


> 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

2021-05-06 Thread J. Gareth Moreton via fpc-devel

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

2021-05-06 Thread Ryan Joseph via fpc-devel


> 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

2021-05-06 Thread J. Gareth Moreton via fpc-devel
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

2021-05-06 Thread Sven Barth via fpc-devel
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

2021-05-06 Thread 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.

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

2021-05-06 Thread J. Gareth Moreton via fpc-devel
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

2021-05-06 Thread 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.

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

2021-05-06 Thread Nikolai Zhubr via fpc-devel

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

2021-05-06 Thread 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.

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

2021-05-06 Thread Nikolai Zhubr via fpc-devel

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

2021-05-06 Thread Ryan Joseph via fpc-devel


> 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

2021-05-06 Thread Ryan Joseph via fpc-devel


> 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

2021-05-06 Thread Sven Barth via fpc-devel

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

2021-05-06 Thread Sven Barth via fpc-devel

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

2021-05-06 Thread Michael Van Canneyt via fpc-devel



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