SRL Archive - Lape

Method overriding is broken in Lape


akarigar

2014-11-20 18:02:51

The following example incorrectly calls TObj.test, @Brandon also thinks this is a bug.
From: Brandon

It's not possible. Lape is broken afaict. The example you gave SHOULD be working. The object is being sliced and the inheritance isn't virtual either: http://en.wikipedia.org/wiki/Object_slicing




type
PObj = ^TObj;

TObj = record
i: integer;
end;

type TComplexObj = record(TObj)
s: string;
end;

procedure TObj.test();
begin
writeLn('TObj.test(): ', self.i);
end;

procedure TComplexObj.test(); override;
begin
inherited();
writeLn('TComplexObj.test(): ', self.i, ' & ', self.s);
end;

procedure callTest(obj: PObj);
begin
obj^.test();
end;

var o: TComplexObj;
begin
o.i := 131;
o.s := 'yes!';
callTest(@o);
end.

tls

2014-11-20 20:34:18

You didn't call it from a TComplexObj pointer. I think that is the intended output.

Gu3st...

2014-11-21 06:58:26

Replacing PObj with ^TComplexObj in callTest does call the overridden procedure.
Object slicing occurs because you ask it to, it seems (aka doesn't seem like a bug).

Awaiting snipe by Brandon telling us all why it's a bug and what causes it… :p

Brandon

2014-11-21 07:46:46

From: tls
You didn't call it from a TComplexObj pointer. I think that is the intended output.


http://ideone.com/JhZtPF //Scroll down and read the output. ("Child Print") is the result. Not the parent print.

http://ideone.com/owDkqy //Not work [probably a compiler problem].


@Zytex;

http://www.freepascal.org/docs-html/ref/refsu29.html


The slicing should NEVER occur if called via a Pointer (shown in the C++ example and Pascal example [if it compiled]). You're not casting the child class to a parent and so the child function call via inheritance should be the resolved. I used the word slicing wrong because the object isn't actually being sliced but it's the easiest way to describe the problem to OP (without having to describe static vs. virtual vs. dynamic inheritance and VTable lookups [which I assumed OP knows but still avoided]). But Lape's inheritance is static and so it's "done by design" but I believe this design decision is wrong/bad.. If it is not a design decision then it is a bug.

The reason why I also believe it is a bug and/or bad design is because for child objects not called through a pointer, you could just give the function a new name instead of override.. Essentially making the override keyword useless/syntactic sugar. Further more, anyone coming from any languages including pascal would expect the child function to be the resolved function when called through a pointer (if virtual function).. This behaviour throws everyone off, except for those not in the know.

Hence why OP was asking..


Another reason I used the word slicing is because the object is essentially sliced since you cannot call the child functions and you cannot access anything of the child, it's basically like a cast; just reversible. You can see this if you use writeln on the parent pointer.

nielsie95

2014-11-21 14:20:38

This is as designed, because there is no virtual method table support in Lape (yet?) and everything is resolved statically. @Brandon;'s examples actually need the (in Lape currently not supported) virtual keyword to make it work. If you inspect the sizes of the types, they will be exactly what you would expect; SizeOf(Integer) and SizeOf(Integer)+SizeOf(string), respectively. Would there be a virtual method table (as is the case with classes/objects), the sizes of the types would be larger.

I agree that the behaviour might be confusing, especially when you are used to working with objects/classes. However, I think it's better to compare Lape records to FPC/Delphi (extended) records, rather than objects or classes.