So, since you said that one thing you said about how you technically aren't suppose to make childs of atom/movable, i fully understand if you don't fix this, but, it's still technically unexpected behavior. =P
/atom/movable/light
mob
verb/testAM()
var/atom/movable/light/thing = new()
world << isobj(thing)
world << istype(thing, /obj)
(you get 1 and 0)
workaround:
#define isobj(thing) istype(thing, /obj)
Edit, I'm almost 100% sure this can't be fixed since atom/movable and obj are the same typeid, so isobj() would be slower if it was made to not use that
Since it doesn't inherit from the /obj type, but from /atom/movable instead, the istype() check is supposed to return false just like it does. But because internally it actually is an obj--it absolutely has to be either an obj or a mob if it descends from /atom/movable--isobj() returns true just like it does.
Basically the obj internal structure and the /obj type are separate entities, but they're meant to stay together. By inheriting directly from /atom/movable you create an object that has the structure without the type. isobj() simply checks whether the value is of internal type 2, an obj, and doesn't concern itself with type inheritance (which also means it's way faster).