Bram Kuijvenhoven wrote:
> 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.

Thanks for the detailed explanation!

So to ensure a valid self inside the instance method, it should be virtual?

If so, what side-effects would this cause when applied across the complete 
class-hierarchy?

And is there a switch to pass to FPC to make all methods virtual?

Thanks!

--
Al

_________________________________________________________________
     To unsubscribe: mail [EMAIL PROTECTED] with
                "unsubscribe" as the Subject
   archives at http://www.lazarus.freepascal.org/mailarchives

Reply via email to