Show quoted text 6 lines
> i := self.names.indexOf(name);
> val := Struct(self.values[i]);
> raises "got untyped expected Struct". Sure, that's why I'm trying to cast... Without casting to Struct, the compiler indeed throws "got pointer expected Struct". I'm very surprised since I already did this.
in first place, you can omit self within the object's methods, as it's
implicitly there.
Right. Just personal preference for expliciteness. (Even if I don't like magic names.)
second, the property Values[] expects a string inside "[]" and not a
number, so you may want to use val := Values[name];
No. Sorry, I was not clear enough. Self here is a Struct, and Struct is custom class type. Its .values attribute is a TFPList holding objects, which also happen to be Struct-s; but they could be any kind of pointed thingies. .names is a TStringList. (*) My issue is I cannot cast a value (thus a struct) back to its Struct type. The compiler refuses. But I can do exactly the same operation, for any reason, with the simpler case appended to the previous post.
third, Values return a string (the rightmost part of the "=" if you read
the items property (or directly l[n])), so you cannot cast it to "Struct".
... see above, and the example. It *is* a Struct.
Show quoted text 27 lines
I think you intend to do something like:
Var
MyStruct: Struct;
MyList: TStringList;
I: Integer;
(...)
MyList := TStringList.Create();
(...)
For I := 0 To 10 Do
Begin
MyStruct := Struct.struct(I);
MyList.AddObject(Format('struct no. %d', [I]), TObject(MyStruct));
End;
{cannot remember whether the casting to TObject is necessary or not, or
any syntax error I might have done, because I'm typing it out of my
mind, after a year or so I haven't written any pascal code... anyway, I
suggest you derive your Struct from TObject. And for a matter of
readability, I also suggest you name it TStruct instead of plainly
Struct, but this is a matter of taste}
(...)
Yes, thank you for this example. I will probably do this later. But as of now, since I did not now TStringList implements the "associated object" features, I use a // TFPList of objects; instead of a TStringList's .Object attribute. hope it's clear. It's exactly the same scheme, in fact, and I doubt there is any loss & again at using the one or the other.
Show quoted text 5 lines
you can now retrieve the objects you added with:
For I := 0 To Pred(MyList.ItemsCount) Do
Begin
MyStruct := Struct(MyList.Objects[I]);
This is precisely what the compiler refuses in my case. To be fully explicite, the above translates in my case (since both container and the values are structs):
MyStructValue := Struct.(StructContainer.values[I]);
Show quoted text 9 lines
...do whatever you like with your struct variable here...
End;
If you need to retrieve your objects using the "names" you need to do
something like:
I := MyList.IndexOfName("struct no. 6");
If(I >= 0)
MyStruct := Struct(MyList.Objects[I]);
Yes, this is the code you commented on top of this post:
Show quoted text 12 lines
> i := self.names.indexOf(name);
> val := Struct(self.values[i]);
bear in mind that free-ing MyList does not free the instances of Struct
you have created and inserted; so you need to do it manually, in another
for-cycle, for example...
For I := 0 To Pred(MyList.ItemsCount) Do
Begin
MyStruct := Struct(MyList.Objects[I]);
MyStruct.Free;
End;
Yes, thank you for this warning. And, believe it or not, this is precisely in the destructor that the compiler refuses my casting. The reason there is no test. The whole .free methoid reads (untested since the compiler blocks):
destructor Struct.free;
{ Free values before freeing the structure itself. }
var i : Integer;
val : Struct;
begin
self.names.destroy;
for i:=0 to self.count-1 do begin
val := Struct(self.values[i]);
val.free;
val := nil;
end;
self.values.destroy;
inherited; // useless???
end;
Or you can descend from TStringList (don't know if this is the best
thing you could do, but...), and add a property ObjectValues, with a
proper Getter and Setter expecting a string instead of an integer; like:
No, this does not match my case. I'd rather have a linked list for names since it is only traversed, to find the index of a value (so the method could follow pointers, instead of computing them like for an array). But I keep the code below, thank you, as an example or property implementation (haven't written any yet).
Show quoted text 25 lines
property ObjectValues[const AName:String]: TObject Read GetObjectValue
write SetObjectValue;
Function TMyStringList.GetObjectValue(const AName:String):TObject;
Var I:Integer;
Begin
Result := Nil;
I := IndexOfName(AName);
If (I >= 0) Then
Result := Objects[I];
End;
Procedure TMyStringList.SetObjectValue(const AName:String; AObject:TObject);
Var I:Integer;
Begin
I := IndexOfName(AName);
If (I >= 0) Then
Objects[I] := AObject;
End;
As I said, take all this with a grain of salt, as I may have written
mistakes and/or forgot something.
Just my 2c, hope this helps.
Thank you very much.
Denis
(*) Struct is in fact the root type of an OO type system. It should be called "Unit" but for any reason the compiler also refuses this name ;-) The OO framework is to be written "in itself", meaning the model only uses its own features to define itself. There is a name for this kind of reflexivity. It is the reason why the content of a Struct is structs. Looks like a joke... Later, even the names will be (instances of a subtype of) Struct. I don't know where this path leads (PascaLisp?), but I'm sure I want to follow it :-) ________________________________
vit esse estrany ☣
spir.wikidot.com