_Release call location for unused function results

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

_Release call location for unused function results

Zoë Peterson
In the code below Bar creates a reference counted object and returns an
interface to it.  Foo calls Bar but doesn't assign the result anywhere.

In Delphi, this produces the result:
   Foo >
   TAutoRelease.Create
   Foo <
   TAutoRelease.Destroy

But in Free Pascal it produces this:
   Foo >
   TAutoRelease.Create
   TAutoRelease.Destroy
   Foo <

If I change Foo to assign the interface to a local variable but don't do
anything with that variable, Free Pascal produces the same results as
Delphi.

Delphi's behavior is what I expected, and allows tricks with triggering
behavior when leaving the current scope.  Barry Kelly has one example on
his blog where he talks about implementing C++'s RAII using it:
http://blog.barrkel.com/2010/01/one-liner-raii-in-delphi.html

Is Free Pascal's behavior intentional?  Can it be changed to match Delphi?

Thanks,
Zoë Peterson
Scooter Software


============================================

program AutoRelease;

{$IFDEF FPC}{$MODE DELPHI}{$ENDIF}
{$APPTYPE CONSOLE}

uses
   Classes,
   SysUtils;

type
   TAutoRelease = class(TInterfacedObject)
     constructor Create;
     destructor Destroy; override;
   end;

constructor TAutoRelease.Create;
begin
   WriteLn('TAutoRelease.Create');
end;

destructor TAutoRelease.Destroy;
begin
   WriteLn('TAutoRelease.Destroy');
   inherited;
end;

function Bar: IInterface;
begin
   Result := TAutoRelease.Create;
end;

procedure Foo;
begin
   WriteLn('Foo >');
   Bar;
   WriteLn('Foo <');
end;

begin
   Foo;
end.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: _Release call location for unused function results

Graeme Geldenhuys-6
On 2018-01-29 22:32, Zoë Peterson wrote:
> Is Free Pascal's behavior intentional?  Can it be changed to match Delphi?

Something I've queried with the FPC developers some 10 years ago. The
Delphi behaviour is undocumented, so developers are relying on a
implementation detail that could change without notice.

FPC, as you noticed, implements such behaviour differently. They can,
because once again, the Delphi behaviour in undocumented.

As someone that also works on Delphi code, the "cool interfaces trick"
so often used in Delphi (eg: to implement a home-grown call stack etc)
doesn't work so nicely with FPC - where you need a interface reference
variable.

Anyway, the FPC team had no intention in changing the behaviour to
something that is undocumented. So we had to learn to live with it.
Maybe you have more luck with them that I did. ;-)

Regards,
   Graeme

--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

My public PGP key:  http://tinyurl.com/graeme-pgp
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: _Release call location for unused function results

Maciej Izak
In reply to this post by Zoë Peterson
2018-01-29 23:32 GMT+01:00 Zoë Peterson <[hidden email]>:
Is Free Pascal's behavior intentional?  Can it be changed to match Delphi?

the topic is well known. I have plan to add new modeswitch for that:

SCOPEDINTERFACEDESTROY

If you like you can try existing patch:


anyway somehow Delphi (undocumented) way seems bad. SCOPEDINTERFACEDESTROY would be big help for legacy code ported from Delphi...

FPC has more elegant alternative way for the same thing, you can simple use *with*:

procedure Foo;
begin
  WriteLn('Foo >');
  with Bar do
  begin
    WriteLn('Foo <');
  end;
end; 

--
Best regards,
Maciej Izak

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: _Release call location for unused function results

Michael Van Canneyt
In reply to this post by Zoë Peterson


On Mon, 29 Jan 2018, Zoë Peterson wrote:

> In the code below Bar creates a reference counted object and returns an
> interface to it.  Foo calls Bar but doesn't assign the result anywhere.
>
> In Delphi, this produces the result:
>   Foo >
>   TAutoRelease.Create
>   Foo <
>   TAutoRelease.Destroy
>
> But in Free Pascal it produces this:
>   Foo >
>   TAutoRelease.Create
>   TAutoRelease.Destroy
>   Foo <
>
> If I change Foo to assign the interface to a local variable but don't do
> anything with that variable, Free Pascal produces the same results as
> Delphi.
>
> Delphi's behavior is what I expected, and allows tricks with triggering
> behavior when leaving the current scope.  Barry Kelly has one example on
> his blog where he talks about implementing C++'s RAII using it:
> http://blog.barrkel.com/2010/01/one-liner-raii-in-delphi.html
>
> Is Free Pascal's behavior intentional?  Can it be changed to match Delphi?
The question is whether Delphi's behaviour is intentional. You are relying
on undocmented behaviour: when does an intermediate temp variable go out of scope?

This is not defined, and the behaviours of Delphi and FPC regarding temp
variables do not match. This is well known since many many years.
see e.g.
https://bugs.freepascal.org/view.php?id=30409

As Maciej wrote, it can be changed.

But relying on what is an implementation detail is ill-advised, and
certainly not robust programming.

Michael.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: _Release call location for unused function results

Maciej Izak
2018-01-30 8:34 GMT+01:00 Michael Van Canneyt <[hidden email]>:
The question is whether Delphi's behaviour is intentional. 

Sadly it is intentional (but undocumented), the facts:

* Barry Kelly compiler guy post
* Works with all known Delphi versions
* I've checked this for NG compiler - also works like in classic Delphi (especially this point means that the "feature" is intentional )

Seems like the SCOPEDINTERFACEDESTROY mode-switch is necessary. The question is:

would we like to enabling this for all Delphi modes?

the approach with "with" for "scoping" seems more proper even in Delphi mode. Probably SCOPEDINTERFACEDESTROY should stay off for all modes including Delphi modes.

--
Best regards,
Maciej Izak

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: _Release call location for unused function results

Marco van de Voort
In our previous episode, Maciej Izak said:
> > The question is whether Delphi's behaviour is intentional.
> Sadly it is intentional (but undocumented), the facts:
>
> * Barry Kelly compiler guy post
> * Works with all known Delphi versions
> * I've checked this for NG compiler - also works like in classic Delphi
> (especially this point means that the "feature" is intentional )

Have you tested this with large methods? The trouble is we only get
reports/code from people for whom the hack succeeded, not from ones that
tried and failed.

I can remember from one of the bugreports or mail threads about very large
procedure bodies (where FPC hit virtual register numbers) that Delphi starts
to deallocate temps earlier depending on procedure size and maybe used
language constructs.  (number of structured temps?) That was mostly strings,
but might also go for interfaces. I can also imagine that one would like
to disable this in case recursion is detected.

> Seems like the SCOPEDINTERFACEDESTROY mode-switch is necessary.

No, one could also simply fix the relevant code.

> question is: would we like to enabling this for all Delphi modes?

Everything that needs this is essentially feature abuse. I would not enable
it by default, but IF for some reason this needs to be added, when enabled
add a permanent note/warning that this is a workaround for broken code.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: _Release call location for unused function results

Maciej Izak
2018-01-30 14:40 GMT+01:00 Marco van de Voort <[hidden email]>:
Have you tested this with large methods? The trouble is we only get
reports/code from people for whom the hack succeeded, not from ones that
tried and failed.

I can remember from one of the bugreports or mail threads about very large
procedure bodies (where FPC hit virtual register numbers) that Delphi starts
to deallocate temps earlier depending on procedure size and maybe used
language constructs.  (number of structured temps?) That was mostly strings,
but might also go for interfaces. I can also imagine that one would like
to disable this in case recursion is detected.

Yes I am aware of this. In the case of interfaces for large methods all seems works as presented for simple example. I was not able to reproduce this problem for interfaces.
 
> Seems like the SCOPEDINTERFACEDESTROY mode-switch is necessary.

No, one could also simply fix the relevant code.

I am not the fan of SCOPEDINTERFACEDESTROY. My first impression about this was : WTF. In some cases is almost impossible to fix large legacy (and often wrong) code base.
 
> question is: would we like to enabling this for all Delphi modes?

Everything that needs this is essentially feature abuse. I would not enable
it by default

+1 . Anyway I am still considering : commit or not :P.

--
Best regards,
Maciej Izak

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: _Release call location for unused function results

Free Pascal - General mailing list
Am 30.01.2018 15:07 schrieb "Maciej Izak" <[hidden email]>:
 
> question is: would we like to enabling this for all Delphi modes?

Everything that needs this is essentially feature abuse. I would not enable
it by default

+1 . Anyway I am still considering : commit or not :P.

While I still don't want to have this switch no matter the legacy codebase affected by it, if we add it we definitely don't add it enabled anywhere. And please, maybe it "ScopedInterfaceRelease", not "-Destroy" as that is what the functionality does. 

Also I remember from some time back that someone (maybe even Jonas) presented an example where Delphi does in fact behave different. I'd need to find that again however. :/

Regards, 
Sven 

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: _Release call location for unused function results

Florian Klaempfl
In reply to this post by Maciej Izak
Am 30.01.2018 um 15:07 schrieb Maciej Izak:

> 2018-01-30 14:40 GMT+01:00 Marco van de Voort <[hidden email] <mailto:[hidden email]>>:
>
>     Have you tested this with large methods? The trouble is we only get
>     reports/code from people for whom the hack succeeded, not from ones that
>     tried and failed.
>
>     I can remember from one of the bugreports or mail threads about very large
>     procedure bodies (where FPC hit virtual register numbers) that Delphi starts
>     to deallocate temps earlier depending on procedure size and maybe used
>     language constructs.  (number of structured temps?) That was mostly strings,
>     but might also go for interfaces. I can also imagine that one would like
>     to disable this in case recursion is detected.
>
>
> Yes I am aware of this. In the case of interfaces for large methods all seems works as presented for
> simple example. I was not able to reproduce this problem for interfaces.
>  
>
>     > Seems like the SCOPEDINTERFACEDESTROY mode-switch is necessary.
>
>     No, one could also simply fix the relevant code.
>
>
> I am not the fan of SCOPEDINTERFACEDESTROY. My first impression about this was : WTF. In some cases
> is almost impossible to fix large legacy (and often wrong) code base.
>  
>
>     > question is: would we like to enabling this for all Delphi modes?
>
>     Everything that needs this is essentially feature abuse. I would not enable
>     it by default
>
>
> +1 . Anyway I am still considering : commit or not :P.

If is implemented, it needs to be clearly documented how it works.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal