6

My question is pretty simple. I have a TList (called queue) containing objects of class CNotif and want to use the method is_alive on those objects.

The problem is, when I use queue.Items[0].is_alive(), I get an error message saying Error: Illegal qualifier.

I'm also confused with the way I can instantiate objects in this TList (and how the way the compiler "knows" that the objects stored are of this type ...)

What I do now is: queue.Add(CNotif.create(timer, title, text, badge)) but I don't think it's supposed to be done that way.

Thank you in advance !

halflings
  • 1,540
  • 1
  • 13
  • 34
  • 5
    Just a sidenote. There is an unwritten convention to name the types with the first char `T`, like `TLama` is type of `Lama`, so for your case it would be `TCNotif` ;-) – TLama Apr 15 '12 at 17:26
  • Isn't it C for Classes and T for "basic" types (like an array or a record) ? – halflings Apr 15 '12 at 21:38
  • Nope, it's for all `T`ypes, including classes, records, enumerations etc. Let's say for everything you have in the `type` section of your code. – TLama Apr 15 '12 at 21:58
  • 1
    Just to clarify, as TLama points out, in your case it would actually be `TNotif` if I'm not mistaken - if the `C` was your prefix intended. But everything after the `T` is all up to you anyway, so technically there's no right or wrong way to name types. Things will still work without the `T` but in Delphi, types are expected to begin with `T`. – Jerry Dodge Apr 16 '12 at 02:38

2 Answers2

10

The problem is, when I use queue.Items[0].is_alive(), I get an error message saying Error: Illegal qualifier.

That's because the compiler has no idea what queue.items[0] is other than a generic pointer (see below).

What I do now is: queue.Add(CNotif.create(timer, title, text, badge)) but I don't think it's supposed to be done that way.

This is exactly the way you need to do it. CNotif.Create constructs a new object, and that object descends from TObject. It compiles fine because your queue.Add call is expecting a pointer, and a Delphi/FreePascal variable containing an object instance is actually a pointer. (Both languages hide the need to dereference using MyObj^ for us.)

To use something in queue.Items, you need to tell the compiler what's in there other than a generic pointer (which of course doesn't have an is_alive method). You do that by typecasting:

CNotif(queue.Items[0]).is_alive

Note: There's a shorter way to use the TList.Items; Items is declared as the default property for the TList, so you can omit it:

queue[0] 

is the same as

queue.Items[0]

and is much easier to type.

Ken White
  • 123,280
  • 14
  • 225
  • 444
6

Unless you're stuck with an old Delphi version, you should look into generics.

In the generics.collection unit there is a TList<T> class that you could use here.

Queue:TList<CNotify>;

...
Begin
  Queue := TList<CNotify>.Create; // remember to clean it up
  Queue.Add(CNotify.Create(...));
  Queue.Add(CNotify.Create(...));

  If Queue[0].isAlive then
    Beep;
End;

I haven't used fpc and lazarus for a while, but in Delphi this is definitely the way to do this. Lists of untyped pointers and type-casts all over the place can become a nightmare to maintain.

Wouter van Nifterick
  • 23,603
  • 7
  • 78
  • 122
  • 2
    +1, but it might be good to mention from D2010+ because there were several problems in D2009 especially with `TList`. – TLama Apr 16 '12 at 00:03
  • 4
    In fpc ObjFPC mode, the syntax is `type TQueue = specialize TFPGList` -- but you can also use Delphi mode which has Delphi syntax (at least since 2.6). – lukstafi Apr 16 '12 at 02:45