[fpc-pascal] stuck with untyped pointer

spir ☣ denis.spir at gmail.com
Fri May 28 22:12:09 CEST 2010


On Fri, 28 May 2010 20:51:10 +0300
Alberto Narduzzi <albertonarduzzi at yahoo.com> wrote:

> >    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.

> 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.

> 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]);

>    ...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:
> >    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).

> 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



More information about the fpc-pascal mailing list