Al Boldi wrote:
Mattias Gaertner wrote:
Al Boldi <[EMAIL PROTECTED]> wrote:
Mattias Gaertner wrote:
Al Boldi <[EMAIL PROTECTED]> wrote:
Flavio Etrusco wrote:
On 6/3/06, Al Boldi wrote:
In the fpc-rtl there is something like this:
procedure TObject.Free;
begin
if self<>nil then self.destroy;
end;
Does this make sense? i.e. How is it possible for self to be
nil?
'Self' isn't a global variable associated with the method, it's
simply a parameter passed implicitly to the method.
This would imply, that we are executing the class method instead of
the object method.
No. The 'Self' of a class method is the class.
The Self=nil test is useful for this case:
var o: TObject;
o:=TObject.Create;
...
o.Free;
o:=nil;
...
o.Free;
The o is given to the method as hidden parameter, accessible via Self.
Only the constructor should be possible to be called w/o self. All
others should be dependent on a valid self, otherwise we get something
like this:
var obj: TObject;
TObject.Free; // this won't compile, which is correct
obj.Free; // this will compile, which is correct,
// and gets warned of not being initialized,
// but the error only gets detected inside
// the class method, which is incorrect,
// as it should have been detected in the
// calling routine during execution.
This problem gets really bad, when you have large class hierarchies, as
the error may only be detected in some deep object without reference to
the causing routine.
Yes, and no.
Yes, because it happens frequently. And no, it is not a big problem,
because the gdb backtrace shows it quite clear.
Michael Van Canneyt wrote:
Al Boldi wrote:
Does FPC have a switch to disallow executing class/definition
methods, and only allow executing object/instance methods?
No. What on earth would be the use of that ?
This would make it easier to detect the causing routine of a
non-initialized self.
I'm not sure, what you mean. It is calling the instance method, not a
class method.
You wish. obj.Free calls the class method regardless of self's validity.
Calling the instance method could ensure a valid self always.
A 'class method' is a method that doesn't need a class instance, i.e. no
'self'. It is declared with the 'class' keyword put before the 'function' or
'procedure' keyword. Other methods get an implicit 'self' parameter passed to
them that points to the object it is called on.
Methods in Pascal are not fields stored in objects! (in some scripting languages, like Lua, this is indeed the case) They are part of the /type/ of the object (its class), and for virtual methods, the actual method called is determined at run time using the object's VMT (more details on that below).
I also think you might forget that Free is not a virtual method. Only virtual
methods can be overridden and use so called 'late binding' through the VMT
(Virtual Method Table) associated with the object the call is made on.
So calling a non-virtual method on a object pointer that is nil, results in a
valid method call with self = nil, but a /virtual/ method call on a object
pointer that is nil will result in an exception because your program will try
to access the VMT of the object. (Note: in fact every object instance has a
pointer to a class record, which in turn holds a pointer to the VMT. For every
class, one such class record is kept in memory with the class name, the VMT,
RTTI (if {$M+}), etc.)
If a method is non-virtual, the compiler derives which classes method to call
from the declared type of the object pointer at hand. (This is why it is a bad
idea to redefine a non-virtual method in a descendant class; the compiler will
complain about this saying you're 'hiding a non-virtual method'.)
It is simply a feature of Object Pascal that non-virtual method calls can be
done on a nil object pointer. You can add a check in such a method if you want.
An example to clear things up:
type
TA = class
procedure Foo;
procedure Bar; virtual;
end;
TB = class(TA)
procedure Foo; // bad plan: hiding virtual method TA.Foo
procedure Bar; override;
end;
...
var
A: TA;
B: TB;
...
A := TA.Create;
B := TB.Create;
A.Foo; // executes TA.Foo with self = A, because A is of declared type TA
B.Foo; // executes TB.Foo with self = B, because B is of declared type TB
A.Bar; // executes TA.Bar with self = A, because A is of actual type TA
B.Bar; // executes TB.Bar with self = B, because B is of actual type TB
A := B;
A.Foo; // still executes TA.Foo with self = A = B, because A is of declared
type TA
B.Foo; // still executes TB.Foo with self = B, because B is of declared type TB
A.Bar; // executes TB.Bar with self = A = B, because A is of actual type TB now!
B.Bar; // executes TB.Bar with self = B, because B is of actual type TB
B.Destroy;
B := nil;
B.Foo; // still executes TB.Foo, now with self = B = nil, because B is of
declared type TB
B.Bar; // causes an exception because the VMT of B = nil cannot be accessed
A.Foo; // still executes TA.Foo, now with self = A, because A is of declared
type TA; note however that the object that A points to has been Destroyed
already, so self = A is an invalid pointer in fact
A.Bar; // causes an exception because the VMT of the invalid pointer A cannot
be accessed (note: I don't know whether Destroy clear the class pointer in the
object instance; the call might still succeed, with unexpected results)
A useful shorthand for A.Free; A := nil; is FreeAndNil(A); Similarly,
A.Free; is a shorthand for if A<>nil then A.Destroy;
As the example shows, the programmer has to take care that once a object is
freed, none of the pointers to it are used! If more that one variable points to
the same object instance, this is indeed not so easy.
Note that unlike e.g. many scripting languages, Pascal has no automatic memory
management.
Regards,
Bram
_________________________________________________________________
To unsubscribe: mail [EMAIL PROTECTED] with
"unsubscribe" as the Subject
archives at http://www.lazarus.freepascal.org/mailarchives