Sign in Join

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

Mailing lists / fpc-pascal / 2010-05

question about class

3 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

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

spir ☣

Hello,

I'm trying to transform a manually implemented type, with pseudo-method as funcs/procs, into an fpc "class" type; and facing numerous issue: namely 3 whole pages of compiler errors ;-). Are there somewhere more or less pedagogic examples of class code?

*self*
Do i need to explicitely name self as param? Is self actually a pointer? If yes, do I need to treat as such, or is this magically handled by the language? Eg self^.prop or self.prop?

*destructor*
Is a destructor required? What is it supposed to do? Deallocation? (but then self disappears in the middle of a method it is the target of...). Isn't it garbage collected when dereferenced?

*type mutual recursion*
One func method returns an object of another type (actualy a record, but I guess it does not make any difference). But this record object holds a pointer to an object of the first type... Similar issue with a param of another method. There was no issue in the non-class version of the same code, since pseudo-methods (and their params and return values) did not need to be pre-declared. By the way: why do we need to pre-declare methods, since they are bound to their type anyway by their name prefixes? (I mean so-called "qualified names" of the form type.methodName).

Denis
________________________________

vit esse estrany ☣

spir.wikidot.com

Reply by email

David Emerson
to spir ☣

I'm no expert so these answers may be a bit off, but I figure any help is nice during US business hours...

Are there somewhere more or less pedagogic examples of class code?

I've never found any. I've learned largely by studying (and occasionally fixing) fpgui code.

*self* Do i need to explicitely name self as param?

Depends on context? I use 'self' for the following:

- if I am inside a 'with' context, and there is another data type with an identical field name, I'll reference self.field_name
- even without a 'with' context I'll sometimes use it to make things easier to read
- to call a procedure which takes a class as a parameter. A particularly common example would be a constructor that requires a parameter which will be its owner: e.g. within a method of a 'window' object I might call Tscrollbar.create (self); so that the window is the owner of the scrollbar... and the scrollbar can look at the window to get its size.

Is self actually a pointer? If yes, do I need to treat as such, or is this magically handled by the language? Eg self^.prop or self.prop?

I'm not sure, but self.method and self.field have always worked fine for me. Never tried to put a caret into the syntax.

*destructor* Is a destructor required? What is it supposed to do? Deallocation? (but then self disappears in the middle of a method it is the target of...).

Do you mean, are you required to *write* a destructor? No, but you can. I use them to destroy child objects.

Or, do you mean, do you need to *call* a destructor? Yes, you do. You should call "Free" rather than "Destroy". I don't recall why.

Isn't it garbage collected when dereferenced?

No, classes are not automatically deallocated when dereferenced. They are pointers, and there may be several references to them (and they are not reference-counted) so there is no automatic deallocation. You need to call Free.

Show quoted text 7 lines
*type mutual recursion* One func method returns an object of another type (actualy a record, but I guess it does not make any difference). But this record object holds a pointer to an object of the first type... Similar issue with a param of another method. There was no issue in the non-class version of the same code, since pseudo-methods (and their params and return values) did not need to be pre-declared.

I'm not sure I understand your question but maybe this is your answer:

a_type = class;
b_type = class;
a_type = class
  b : b_type;
  end;
b_type = class
  a : a_type;
  end;
By the way: why do we need to pre-declare methods, since they are bound to their type anyway by their name prefixes? (I mean so-called "qualified names" of the form type.methodName).

You mean ... as opposed to a non-class procedure, which could simply be defined in the implementation section of a unit, without any mention in the interface? I don't know all the proper terminology, but my best guess is this: when the compiler creates the framework for the class, it needs to have everything available. Once it gets to the implementation section, it's too late to be adding more methods into that framework, or VMT, or whatever the thing is called.

Hope this was helpful and not terribly incorrect!

Cheers,
David.

Reply by email

Andrew Hall
to David Emerson
> Do i need to explicitely name self as param?

self is a reserved keyword which represents the reference to the object of context (much the same as using "result" in a function) - it is understood by the compiler and does not need to be specified.

> Is self actually a pointer? If yes, do I need to treat as such, or is this > magically handled by the language? Eg self^.prop or self.prop?

Self is a pointer. Delphi (and FPC which it is based upon) treats the dereference ^ as implicit.

> *destructor* > Is a destructor required? What is it supposed to do? Deallocation? (but then > self disappears in the middle of a method it is the target of...).

A destructor is only required if your object has its own private structures to finalise/dispose/etc. If you do not need your own destructor, the virtual destructor in TObject will suffice.

Or, do you mean, do you need to *call* a destructor? Yes, you do. You should call "Free" rather than "Destroy". I don't recall why.

Free is used because it is a static method and can be safely called against a nil object reference (Destroy is virtual, and so will raise an access violation when the application attempts to access the object's VMT). Free simply checks whether self is nil... "if self nil then Destroy"

> Isn't it garbage collected when dereferenced?

As David says, objects are not reference counted. You must use interfaces (which are usually implemented via TInterfacedObject) for that feature. Note that interfaces are not "garbage collected", per se - they are immediately released when the reference count hits zero. This is in contrast to other languages where objects are cleared by a "garbage collection" process triggered either intermittently, or when other conditions are met (eg. low memory).

Show quoted text 7 lines
> *type mutual recursion* > One func method returns an object of another type (actualy a record, but I > guess it does not make any difference). But this record object holds a pointer > to an object of the first type... Similar issue with a param of another > method. There was no issue in the non-class version of the same code, since > pseudo-methods (and their params and return values) did not need to be > pre-declared.

Where there are cross references to classes in the same section, one or both can be declared TMyClass = class; as long as the full declaration appears later in the same section. This allows two classes to reference each other. This does not work with records, however. Note - that generic pointers, or using base class references (like TObject) in the declaration can also be useful approaches to issues around access to class types (which can be cast in the implementation "fMyTObject as TMySpecificObject".

> By the way: why do we need to pre-declare methods, since they are bound to > their type anyway by their name prefixes? (I mean so-called "qualified names" > of the form type.methodName).

The only part of a unit visible to another unit is the interface section. Everything other units might touch must be declared there (same as non-class procedures and functions). Visibility of fields and methods in a class is controlled using "published/public/protected/public"

Regards Andrew.

Reply by email