magic-lang / rock

ooc compiler written in ooc
http://ooc-lang.org/
MIT License
14 stars 4 forks source link

Is operator `as` unreliable when testing for inheritance ? #79

Closed ghost closed 7 years ago

ghost commented 7 years ago
use base

Base: abstract class {
    init: func
    doit: abstract func
}

GoodClass: class extends Base {
    init: func
    doit: override func { "good" println() }
}

BadClass: class extends Base {
    init: func
    doit: override func { "VERY BAD" println() }
}

instance: Base
instance = BadClass new()
if (instance as GoodClass)
    instance doit()

output:

VERY BAD

Is it unsafe to use operator as to test for a is a kind of - type of relation ? I would expect instance as GoodClass to fail because instance is an object of the BadClass. Do I have an error somewhere in my code (or are my assumptions about the "as" operator incorrect) ? @thomasfanell

thomasfanell commented 7 years ago

as is not intended to be used this way I don't think, so no, I would not trust it. I would instead use

if (instance instanceOf(GoodClass))
    instance doit()
ghost commented 7 years ago

OK, thanks. Sometimes in our "main" code base we use as without checking for instanceOf before that. But I guess we can close this one.

marcusnaslund commented 7 years ago

Indeed, as is used for casting to another type, not for checking current type. I think you may cast any class to any class and it won't fail until you try to use it the wrong way.

alexnask commented 7 years ago

Just to be clear, if you are familiar with C++ terms, as is a static cast (C cast), not a dynamic cast (it does not return null if the object you are casting is not of the type you are casting to).

You could probably overload it to have this behavior though, something like:

operator <T> as (obj: Object) -> T {
    if (obj instanceOf(T)) {
        obj as T
    } else {
        null
    }
}

would probably work although I'm not quite sure, I'm a bit rusty on the rules on overloading 'as'.

alexnask commented 7 years ago

Also, much cleaner than using instanceOf + cast:

match obj {
    case entity: Entity => doStuff(entity)
}

(Although it can be cumbersome if you only need to test for one type)

ghost commented 7 years ago

Yeah I don't know why but I was under the impression that your "overloaded" implementation was the default in ooc for Objects :/