Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2017-04

Out of scope method?

22 messages · 5 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Ryan Joseph

Does it exist now or has it ever been discussed that a method in TObject could be called when an instance of an object goes out of scope? It’s common to clean up objects in a function body after the function exits and calling a method would be a nice way to handle this. I think c++ has such a feature but I never heard of it in Pascal.

Regards,
Ryan Joseph

Reply by email

Tony Whyman
to Ryan Joseph

Isn't this what a COM Interface does - or at least a descendent of TInterfacedObject?

Tony Whyman

MWA

Ryan Joseph wrote 9 lines
Does it exist now or has it ever been discussed that a method in TObject could be called when an instance of an object goes out of scope? It’s common to clean up objects in a function body after the function exits and calling a method would be a nice way to handle this. I think c++ has such a feature but I never heard of it in Pascal. Regards, Ryan Joseph _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply by email

Ryan Joseph
to Tony Whyman
Show quoted text 5 lines
On Apr 6, 2017, at 3:45 PM, Tony Whyman wrote: Isn't this what a COM Interface does - or at least a descendent of TInterfacedObject? Tony Whyman

No idea. Examples?

Regards,
Ryan Joseph

Reply by email

Sven Barth
to Ryan Joseph: Does it exist now or has it ever been discussed that a method in TObject could be called…
"Ryan Joseph" wrote
Does it exist now or has it ever been discussed that a method in TObject

could be called when an instance of an object goes out of scope? It’s common to clean up objects in a function body after the function exits and calling a method would be a nice way to handle this. I think c++ has such a feature but I never heard of it in Pascal.

It's a difficult topic, cause in Object Pascal class instances are always on the heap while in C++ they might be on the stack as well. Thus a C++ compiler will insert calls to the destructor of such an object if it goes out of scope.

In Object Pascal currently only reference counted interfaces and (new in trunk) records with management operators provide this feature.

Regards,
Sven

Reply by email

Tony Whyman
to Ryan Joseph: No idea. Examples? Ryan Joseph

See http://freepascal.org/docs-html/current/ref/refse48.html#x101-1230007.7 for an example.

See also http://wiki.freepascal.org/How_To_Use_Interfaces

Ryan Joseph wrote 14 lines
> On Apr 6, 2017, at 3:45 PM, Tony Whyman wrote: > > Isn't this what a COM Interface does - or at least a descendent of TInterfacedObject? > > Tony Whyman No idea. Examples? Regards, Ryan Joseph _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply by email

Ryan Joseph
to Sven Barth: could be called when an instance of an object goes out of scope? It’s common to clean…
Show quoted text 5 lines
On Apr 6, 2017, at 4:26 PM, Sven Barth via fpc-pascal wrote: It's a difficult topic, cause in Object Pascal class instances are always on the heap while in C++ they might be on the stack as well. Thus a C++ compiler will insert calls to the destructor of such an object if it goes out of scope. In Object Pascal currently only reference counted interfaces and (new in trunk) records with management operators provide this feature.

I see, but since there is a reference to an instance on the stack wouldn’t it be trivial for the compiler to invoke a method on TObject descendants when they go out of scope? If it does it for compiler types like dynamic arrays I imagine it could do the same for classes.

Regards,
Ryan Joseph

Reply by email

Ryan Joseph
to Tony Whyman: See http://freepascal.org/docs-html/current/ref/refse48.html#x101-1230007.7 for an…
Show quoted text 6 lines

"All COM interfaces use reference counting. This means that whenever an interface is assigned to a variable, it’s reference count is updated. Whenever the variable goes out of scope, the reference count is automatically decreased. When the reference count reaches zero, usually the instance of the class that implements the interface, is freed.”

Shouldn’t destroy be called in this example when TestScope exists?

type
	TScopeObject = class (TInterfacedObject)
		destructor Destroy; override;
	end;
destructor TScopeObject.Destroy;
begin
	writeln('dead');
	inherited Destroy;
end;
procedure TestScope;
var
	scope: TScopeObject;
begin
	scope := TScopeObject.Create;
end;

Regards,
Ryan Joseph

Reply by email

Marco van de Voort
to Ryan Joseph

In our previous episode, Ryan Joseph said:

Show quoted text 8 lines
> See http://freepascal.org/docs-html/current/ref/refse48.html#x101-1230007.7 > for an example. > > See also http://wiki.freepascal.org/How_To_Use_Interfaces "All COM interfaces use reference counting. This means that whenever an interface is assigned to a variable, it?s reference count is updated. Whenever the variable goes out of scope, the reference count is automatically decreased. When the reference count reaches zero, usually the instance of the class that implements the interface, is freed.? Shouldn?t destroy be called in this example when TestScope exists?

No, since you don't declare an interface variable, but a class variable.

There are a zillion Delphi faqs about this, but the crux is to use

var
  scope:IInterface;

And reference counting as garbage collection method has been discussed to dead on various maillists and forums. Both Delphi and Lazarus/FPC.

Reply by email

Ryan Joseph
to Marco van de Voort
Show quoted text 11 lines
On Apr 6, 2017, at 5:09 PM, Marco van de Voort wrote: No, since you don't declare an interface variable, but a class variable. There are a zillion Delphi faqs about this, but the crux is to use var scope:IInterface; And reference counting as garbage collection method has been discussed to dead on various maillists and forums. Both Delphi and Lazarus/FPC.

Hmm, that sounds like a hack. Is the verdict this is generally a bad idea? I was just curious about it and it seems like a reasonable feature a language may have.

Regards,
Ryan Joseph

Reply by email

Marco van de Voort
to Ryan Joseph

In our previous episode, Ryan Joseph said:

Show quoted text 5 lines
> > And reference counting as garbage collection method has been discussed to > dead on various maillists and forums. Both Delphi and Lazarus/FPC. Hmm, that sounds like a hack. Is the verdict this is generally a bad idea?

There is a reason why C++ only applies the basic RAII to stack objects: they can't form cycles, and the time required is fairly predictable.

As soon as you allow references and thus complete, complex structures on the heap this changes.

There are ways around this (by marking some references as weak as in ARC), but in general it is not simple. Delphi's mobile compilers use this.

I was just curious about it and it seems like a reasonable feature a language may have.

Search the web for more info. There is enough info on automatic memory out there to satisfy any curiousity for years :_)

Reply by email

Sven Barth
"Ryan Joseph" wrote 6 lines
> On Apr 6, 2017, at 4:26 PM, Sven Barth via fpc-pascal < wrote: > > It's a difficult topic, cause in Object Pascal class instances are

always on the heap while in C++ they might be on the stack as well. Thus a C++ compiler will insert calls to the destructor of such an object if it goes out of scope.

> > In Object Pascal currently only reference counted interfaces and (new

in trunk) records with management operators provide this feature.

I see, but since there is a reference to an instance on the stack

wouldn’t it be trivial for the compiler to invoke a method on TObject descendants when they go out of scope? If it does it for compiler types like dynamic arrays I imagine it could do the same for classes.

Arrays are reference counted, class instances are not. So if the compiler would blindly free the instance after it goes out of scope if might free something that another code part still uses.

Regards,
Sven

Reply by email

Marcos Douglas B. Santos
to Ryan Joseph: Hmm, that sounds like a hack. Is the verdict this is generally a bad idea? I was just…

Hi Ryan,

Ryan Joseph wrote
Hmm, that sounds like a hack. Is the verdict this is generally a bad idea? I was just curious about it and it seems like a reasonable feature a language may have.

I can guarantee that reference counting is not a bad idea. I have been using this for years and in my own code I do not use Free method anymore (only if I need to use some classes of RTL or some 3rd libs/frameworks), internally, on private methods.

But you need to code using another approach, another mindset...

Best regards,
Marcos Douglas

Reply by email

Ryan Joseph
to Sven Barth: always on the heap while in C++ they might be on the stack as well. Thus a C++ compiler…
On Apr 6, 2017, at 7:45 PM, Sven Barth via fpc-pascal wrote: Arrays are reference counted, class instances are not. So if the compiler would blindly free the instance after it goes out of scope if might free something that another code part still uses.

I was thinking about just calling a method notifying the object it went out of the scope it was declared in. The user could then keep track of ref counting themselves and choose how to handle the case. Personally I want to enable this manually on some objects that I know I didn’t outside of the scope and that would be a handy way to manage this.

Regards,
Ryan Joseph

Reply by email

Ryan Joseph
to Marcos Douglas B. Santos: I can guarantee that reference counting is not a bad idea. I have been using this for…
Show quoted text 8 lines
On Apr 6, 2017, at 8:13 PM, Marcos Douglas B. Santos wrote: I can guarantee that reference counting is not a bad idea. I have been using this for years and in my own code I do not use Free method anymore (only if I need to use some classes of RTL or some 3rd libs/frameworks), internally, on private methods. But you need to code using another approach, another mindset...

What method are you using? I found some examples for Delphi that didn’t seem to work in Free Pascal.

Currently I’ve implemented something similar to that found in the Objective-C frameworks called autoreleasing which adds the object to a pool which is drained and the objects freed at the end of every event cycle (after it’s left scope for certain). That works pretty well actually (anyone else ever do this in Pascal?) but the same thing could be achieved with less overhead if the compiler told me when an instance left scope. Specially in a few cases you could load up the pool too large and cause performance problems so I need to be careful of that.

Regards,
Ryan Joseph

Reply by email

Marcos Douglas B. Santos
to Ryan Joseph
Ryan Joseph wrote 14 lines
> On Apr 6, 2017, at 8:13 PM, Marcos Douglas B. Santos wrote: > > I can guarantee that reference counting is not a bad idea. > I have been using this for years and in my own code I do not use Free > method anymore (only if I need to use some classes of RTL or some 3rd > libs/frameworks), internally, on private methods. > > But you need to code using another approach, another mindset... What method are you using? I found some examples for Delphi that didn’t seem to work in Free Pascal. Currently I’ve implemented something similar to that found in the Objective-C frameworks called autoreleasing which adds the object to a pool which is drained and the objects freed at the end of every event cycle (after it’s left scope for certain). That works pretty well actually (anyone else ever do this in Pascal?) but the same thing could be achieved with less overhead if the compiler told me when an instance left scope. Specially in a few cases you could load up the pool too large and cause performance problems so I need to be careful of that.

First of all, you should use interfaces variables, always. Sometimes you will have memory leaks and will think that ref counting not work. See an example:

=== code ===
function TFoo.Execute(const Name: string): string;
begin
  Result := TAction.Create(TTask.Create(Name)).Execute.ToString;
end;
=== end ===

Even if TAction implement an IAction interface, you will have a memory leak here because you don't have an variable (a: IAction) receiving an instance of TAction.

I am talking about this:

=== code ===
function TFoo.Execute(const Name: string): string;
var
  A: IAction;
begin
  A := TAction.Create(TTask.Create(Name));
  Result := A.Execute.ToString;
end;
=== end ===

Pretty clear, right?

Because this "problem" I have a "pattern" that I called "New Method".

You can see how it works in my article:
(you need to translate from Portuguese)
http://objectpascalprogramming.com/posts/interfaces-e-o-metodo-estatico-new/

Best regards,
Marcos Douglas

Reply by email

Ryan Joseph
to Marcos Douglas B. Santos
Show quoted text 9 lines
On Apr 6, 2017, at 8:54 PM, Marcos Douglas B. Santos wrote: Pretty clear, right? Because this "problem" I have a "pattern" that I called "New Method". You can see how it works in my article: (you need to translate from Portuguese) http://objectpascalprogramming.com/posts/interfaces-e-o-metodo-estatico-new/

This sounds highly prone to errors to be honest. Don’t you lose all type checking also? That would have to be deal breaking I would think.

Regards,
Ryan Joseph

Reply by email

Marcos Douglas B. Santos
to Ryan Joseph
Ryan Joseph wrote 13 lines
> On Apr 6, 2017, at 8:54 PM, Marcos Douglas B. Santos wrote: > > Pretty clear, right? > > Because this "problem" I have a "pattern" that I called "New Method". > > You can see how it works in my article: > (you need to translate from Portuguese) > http://objectpascalprogramming.com/posts/interfaces-e-o-metodo-estatico-new/ This sounds highly prone to errors to be honest. Don’t you lose all type checking also? That would have to be deal breaking I would think.

Lose type checking?
Of course not. You still use the same language, interfaces, classes...

Don't confuse "New, the function" with "New, a method in a class".

Reply by email

Ryan Joseph
to Marcos Douglas B. Santos
Show quoted text 6 lines
On Apr 6, 2017, at 9:42 PM, Marcos Douglas B. Santos wrote: Lose type checking? Of course not. You still use the same language, interfaces, classes... Don't confuse "New, the function" with "New, a method in a class".

I should say that you need to have a matching interface for all your classes, and if not then you’ll lose type checking. IAction needs to have all the methods in TAction for type checking to work right?

Regards,
Ryan Joseph

Reply by email

Marcos Douglas B. Santos
to Ryan Joseph
Ryan Joseph wrote 9 lines
> On Apr 6, 2017, at 9:42 PM, Marcos Douglas B. Santos wrote: > > Lose type checking? > Of course not. You still use the same language, interfaces, classes... > > Don't confuse "New, the function" with "New, a method in a class". I should say that you need to have a matching interface for all your classes, and if not then you’ll lose type checking.

Yes, you need.
IMHO, casting is not a good option to use in object-oriented programming.

IAction needs to have all the methods in TAction for type checking to work right?

In fact is the opposite:
TAction needs to have all methods that IAction have. This TAction class in the example is not the same class in RTL.

You shouldn't have so many methods in just one class. So, it is simple implement all methods of an interface.

Best regards,
Marcos Douglas

Reply by email

Ryan Joseph
to Marcos Douglas B. Santos
Show quoted text 8 lines
On Apr 6, 2017, at 10:01 PM, Marcos Douglas B. Santos wrote: In fact is the opposite: TAction needs to have all methods that IAction have. This TAction class in the example is not the same class in RTL. You shouldn't have so many methods in just one class. So, it is simple implement all methods of an interface.

Ouch, that’s far from a good solution then imo and the auto release pool concept from Cocoa is less work to implement and safer even. A direct compiler notification would be best though.

Regards,
Ryan Joseph

Reply by email

Marcos Douglas B. Santos
to Ryan Joseph
Ryan Joseph wrote 8 lines
> In fact is the opposite: > TAction needs to have all methods that IAction have. > This TAction class in the example is not the same class in RTL. > > You shouldn't have so many methods in just one class. > So, it is simple implement all methods of an interface. Ouch, that’s far from a good solution then imo and the auto release pool concept from Cocoa is less work to implement and safer even. A direct compiler notification would be best though.

Well, it's depends the point of view. :)
But if you've already got your answer, follow it: use the auto release pool concept.

Best regads,
Marcos Douglas

Reply by email

Tony Whyman
to Ryan Joseph: I should say that you need to have a matching interface for all your classes, and if not…

Ryan,

If you want an example of a complete API implemented using reference counted interfaces than you could do worse than look at my Firebird Pascal API (See https://www.mwasoftware.co.uk/fb-pascal-api).

It's fully documented and works with both FPC and Delphi.

Tony Whyman
MWA

Ryan Joseph wrote 15 lines
> On Apr 6, 2017, at 9:42 PM, Marcos Douglas B. Santos wrote: > > Lose type checking? > Of course not. You still use the same language, interfaces, classes... > > Don't confuse "New, the function" with "New, a method in a class". I should say that you need to have a matching interface for all your classes, and if not then you’ll lose type checking. IAction needs to have all the methods in TAction for type checking to work right? Regards, Ryan Joseph _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply by email