Here is the code:
type
BaseObj {.exportc.} = object of RootObj
base:string
BasePtr {.exportc.} = ptr BaseObj
DerivedObj {.exportc.} = object of BaseObj
derived:string
DerivedPtr {.exportc.} = ptr DerivedObj
method show(o:BasePtr) {.base.} =
echo "show:Base"
method show(o:DerivedPtr) =
echo "show:Derived"
var o1:DerivedPtr = cast[ptr DerivedObj](alloc0(DerivedObj.sizeof))
o1.show()
Looks like show(o:DerivedPtr) is not called on o1.
Taking a look at the generated code:
T1_ = (void*)0;
T1_ = alloc0_4cubgSerkjpuLcj5MXjiLw_2(((NI)chckRange(((NI)sizeof(DerivedObj)), ((NI) 0), ((NI) 2147483647))));
o1_y0GlnUoNHJAJQrOKtO2j3Q = ((DerivedObj*) (T1_));
//
nimln_(18, "main.nim");
T2_ = (BaseObj*)0;
T2_ = &o1_y0GlnUoNHJAJQrOKtO2j3Q->Sup;
show_liMlsYHT9cVSmRljjtfubDw(T2_);
It looks like the compiler tries to get a BasePtr instead of a DerivedPtr and then call show for that one.
The code finally fails in the isObjWithCache function at this line:
if (!((*obj).base == subclass)) goto LA7_;
because obj is null.
Any ideas what could be the issue?
The reason for that is that type field of the allocated object is not initialized properly. Here's a quick hack:
type
Foo = ptr object {.inheritable.}
Bar = ptr object of Foo
proc allocObj(t: typedesc): t =
# const sz = sizeof(result[])
result = cast[t](alloc0(sizeof(result[])))
let typ = getTypeInfo(result[])
{.emit: """
`result`->Sup.m_type = `typ`;
""".}
method a(f: Foo) {.base.} =
echo "Foo.a"
method a(f: Bar) =
echo "Bar.a"
let f: Foo = allocObj(Bar)
f.a()
Though you probably should keep to regular ref objects :)
Thank you @yglukhov !
Shouldn't this be done properly by the compiler?
This still doesn't work if you add a third one to the mix:
type
Foo = ptr object {.inheritable.}
Bar = ptr object of Foo
Other = ptr object of Bar
proc allocObj(t: typedesc): t =
# const sz = sizeof(result[])
result = cast[t](alloc0(sizeof(result[])))
let typ = getTypeInfo(result[])
{.emit: """
`result`->Sup.m_type = `typ`;
""".}
method a(f: Foo) {.base.} =
echo "Foo.a"
method a(f: Bar) =
echo "Bar.a"
method a(f: Other) =
echo "Other.a"
let f: Foo = allocObj(Other)
f.a()
Compile error:
error C2039: 'm_type': is not a member of 'tyObject_BarcolonObjectType__6GfTvzixTYAw9cUc8nAxKIQ'
How can this be done in a reliable way?
If you want reliability, you should initialize it explicitly. E.g:
type
BaseObj {.exportc.} = object of RootObj
base:string
BasePtr {.exportc.} = ptr BaseObj
DerivedObj {.exportc.} = object of BaseObj
derived:string
DerivedPtr {.exportc.} = ptr DerivedObj
method show(o:BasePtr) {.base.} =
echo "show:Base"
method show(o:DerivedPtr) =
echo "show:Derived"
var o1:DerivedPtr = cast[ptr DerivedObj](alloc0(DerivedObj.sizeof))
o1[] = DerivedObj()
o1.show()
Since you're initialing it anyway, you could use alloc instead of alloc0 as well.
My updated snippet with @GULPF's idea:
type
Foo = ptr object {.inheritable.}
Bar = ptr object of Foo
proc allocObj(t: typedesc): t =
result = cast[t](alloc0(sizeof(result[])))
result[] = type(result[])()
method a(f: Foo) {.base.} =
echo "Foo.a"
method a(f: Bar) =
echo "Bar.a"
let f: Foo = allocObj(Bar)
f.a()