About Monkey 2 › Forums › Monkey 2 Programming Help › Operator To : Cast Self to Derived Class
This topic contains 7 replies, has 3 voices, and was last updated by 
 arpie
 1 year, 5 months ago.
- 
		AuthorPosts
 - 
		
			
				
November 12, 2017 at 9:53 pm #11663
This results in a memory access violation at runtime :
Monkey123456789101112131415161718192021Class BaseThingOperator To:DerivThing()Return cast<DerivThing>(Self) '<-- This fails at runtime (memory access violation)EndField name:String = "Default"End ClassClass DerivThing Extends BaseThingMethod WriteName()Print(name)End MethodEnd ClassLocal test:BaseThing = New DerivThingLocal test2:DerivThing = testtest2.WriteName()test.name = "DoesItWork"test2.WriteName()But this is fine :
Monkey12Local test:BaseThing = New DerivThing()Local test2:DerivThing = cast<DerivThing>(test)And this also appears to work :
Monkey12345678910111213141516171819202122Class BaseThingOperator To:DerivThing()Local slf := SelfReturn cast<DerivThing>(cast<DerivThing Ptr>(VarPtr slf)[0])EndField name:String = "Default"End ClassClass DerivThing Extends BaseThingMethod WriteName()Print(name)End MethodEnd ClassLocal test:BaseThing = New DerivThingLocal test2:DerivThing = testtest2.WriteName()test.name = "DoesItWork"test2.WriteName()Is the failing of cast<DerivThing>(Self) a bug?
Is my convoluted casting via a VarPtr actually hiding a subtle gotcha that I haven’t noticed that will bite me later if I use this code (assuming, of course, I implement checks that the object is definitely of the right subclass before I cast it)?
TIA
November 12, 2017 at 10:26 pm #11664Sort of a bug, it’s actually recursing to death as To:Derived is calling Cast<Derived> which is calling To:Derived etc etc.
Not sure of allowing operator To to downcast is such a great idea, could live without it myself but will think about it.
(VarPtr slf)[0])
Please don’t use this anymore, it’ll probably be going soon, along with any sort of ‘Object Ptr’ types.
If you really, really need the adress of an object, you can now use Cast<Void Ptr>( obj ) but of course be careful as the returned pointer will become invalid if the object is GCed, ie: it’s up to you to keep the object alive while you are using the pointer.
November 12, 2017 at 11:15 pm #11665Getting a memory access violation was a surprise – you usually do a very thorough job, Mark, of catching this sort of thing at compile time and giving us useful, to-the-point error messages!
I agree, I could live without downcasting in Operator To, but I don’t see that as a reason not to ‘fix’ this ‘sort-of-bug’ if it is not too complicated (when you have 5 minutes to spare :). I could also live without ever doing any type casting at all… but one day I might wish it was availaible!
So for now, to make this work, I can do it like this :
Monkey1234Operator To:DerivThing()Local thing := SelfReturn Cast<DerivThing>(Cast<Void Ptr>(thing))End?
Actually, this also seems to work :
Monkey123Operator To:DerivThing()Return Cast<DerivThing>(Cast<Void Ptr>(Self))EndIs there any reason I shouldn’t use this?
November 12, 2017 at 11:21 pm #11666Why wouldn’t you just make the dynamic cast outside of the class to begin with? Even then, if you need to dynamically cast to a derived class from the base class, why not put the functionality you need in the base class to begin with… At the very least, why aren’t you using ‘Virtual’ methods instead of casting? Dynamic casting is slower, so you don’t have that excuse.
This looks like a design smell.
November 12, 2017 at 11:24 pm #11667Having just praised your error messages, I just typed :
Local a = 15
And got the error ‘Expecting end of line’, which seems a bit cryptic.
I’m sure it used to tell me I had missed out the variable type specifier (or := operator). Have I imagined that?
Sorry, I’ve gone off topic!
November 12, 2017 at 11:53 pm #11668@immutableoctet I agree it smells bad on the first sniff… but actually I think in this particular use case it makes sense.
I have an index (StringMap) of similar objects (all subtypes of a common base class). Inserting objects into the index is easy because subtypes automatically get ‘cast’ to their base class. Even then, I have some subtypes that require a bit of special treatment when added to the index, which I can do by overloading the Add() method. Most of the time, all members of this index can be called via virtual methods (indeed I often iterate over the list, calling the virtual methods).
But occasionally, I want to be able to use the extra (non-virtual) methods available in the subtypes from within more specialised code. This is rare enough that I don’t want to bump up that functionality into the base class.
In reality, all I am trying to do is save a little bit of typing during assignment :
Local thing:Derived
thing = Cast<Derived>(GetFromIndex(id))or
Local thing:Derived
thing = GetDerivedFromIndex(id)can be more succinctly written as :
Local thing:Derived
thing = GetFromIndex(id)But the latter requires an implicit cast (which I am trying to squeeze into an Operator To method).
Another way to look at it is that downcasting in an Operator To method when fetching items from the index seems to me to be a direct analogue to overloading the Add() methods for inserting items.
I think for now I am going to go the route of using GetDerivedFromIndex() methods, as this also allows me to do some type checking before doing a cast, which is not possible using an explicit cast.
November 13, 2017 at 7:13 am #11673Have you tried using generic methods, and making ‘GetFromIndex’ take ‘Derived’ as an argument?
Monkey12Local thing:= GetFromIndex<Derived>(id)Then you can have ‘GetFromIndex’ perform a cast to T, where T is ‘Derived’ in this case.
November 13, 2017 at 9:26 pm #11684That would probably work, too but I think it will still be a bit clumsy. I’ll keep playing around. I really need to stop getting hung up on programming constructs and actually get on with writing a game
 - 
		AuthorPosts
 
You must be logged in to reply to this topic.