Casting question
Monkey Forums/Monkey Programming/Casting question
| ||
Hi all, just checking that the following isn't supposed to work. I'm pretty sure it shouldn't work and I tested it to confirm that, but I needed a sanity check. Thx! Let's say you have a class called A and you make a class called B extended from A. Then you do this: Local newB:B = B(new A) newB ends up as null because the case failed because the code can't "upgrade" A into B right? Here's an example. The print statement prints 1 because newB is null. Strict Import mojo Function Main:Int() Local newB:B = B(New A) Print Int(newB = null) Return 0 End Class A Field x:Int End Class Class B Extends A Field y:Int End Class Basically what I'm actually trying to do is create instances by cloning a template. Normally I'd just use a prototype instance and clone that but the template is extended from another class and I need to clone values from the base class and the extended class. I hoped a simple cast could be applied to the base class instance before I copied the extended class's values to the instance, but realised that would probably fail (hence my test above). So I figure I've either got to use a Factory Class which I pass into the base class when I clone it or use generics somehow. |
| ||
OK here's my Factory Class example. Am I doing this right or is it horrible? Note that the cast to B now succeeds:Strict Import mojo Function Main:Int() Local newB:B = New B 'template Local newInstance:B = B(newB.Clone()) Print Int(newInstance=Null) Return 0 End Class A Method Clone:A( f:Factory ) Local clone:A = f.CreateInstance() 'copy fields Return clone End Method End Class B Extends A Method Clone:A( f:Factory = Null ) If f=Null Then f = New BFactory Local b:B = B(Super.Clone(f)) 'copy fields Return b End Method End Interface Factory Method CreateInstance:A() End Class AFactory Extends Factory Method CreateInstance:A() Return New A End End Class BFactory Implements Factory Method CreateInstance:A() Return New B End End Or maybe this where I'm using a different method called CloneB that returns B to avoid having to typecast outside of the clone method. Ideally I'd have just used a method called Clone:B( f:Factory = Null ) but the compiler won't let me override the bass class Clone method due to the different return type. Strict Import mojo Function Main:Int() Local newB:B = New B 'template Local newInstance:B = newB.CloneB() Print Int(newInstance=Null) Return 0 End Class A Method Clone:A( f:Factory ) Local clone:A = f.CreateInstance() 'copy fields Return clone End Method End Class B Extends A Method CloneB:B( f:Factory = Null ) If f=Null Then f = New BFactory Local b:B = B(Super.Clone(f)) 'copy fields Return b End Method End Interface Factory Method CreateInstance:A() End Class AFactory Extends Factory Method CreateInstance:A() Return New A End End Class BFactory Implements Factory Method CreateInstance:A() Return New B End End |
| ||
newB ends up as null because the case failed because the code can't "upgrade" A into B right? A is not B, but B is A. That's why you can cast a B instance up to A and from that down to B again, but cannot cast an A instance to B. I believe that's the answer you're looking for, although to be honest, I wasn't sure what the question was. |
| ||
Yes that's the confirmation I needed. I was pretty sure that was the case but I saw some other code example (probably untested) on the forums using casting like that and got confused. Still, the main issue now is, is my factory code good or horrible? How would you do it? |
| ||
I can't really comment on that question, as it's very opinionated. Whatever works, works. Don't get too worked up over something that's working. ;} |
| ||
does your question focus on this?Local b:B = B(Super.Clone(f)) Yes, this is the way to do it. It's too bad that monkey does not allow extending a base class method with a derived class. Class A Method CloneMe:A() Return New A End End Class B Extends A Method CloneMe:B() ''Illegal in Monkey unless you return 'A', then cast Return New B End End |
| ||
Thought of an alternative approach, typed into browser so not tested, requires reflection.Class BaseItem Method Init : BaseItem( copy : BaseItem ) Abstract Method Copy : BaseItem( copy : BaseItem ) Local this : Object = GetClass( copy ).NewInstance() Return BaseItem( this ).Init( copy ) End Method End Class Class ItemA Extends BaseItem Field x : int Method Init : BaseItem( copy : BaseItem ) If copy <> Null Local this : ItemA = ItemA( copy ) If this Self.x = this.x Return Self Endif Endif '// default init Self.x = 100 Return Self End Method End Class Class ItemB Extends ItemA Field y : Int Method Init : BaseItem( copy : BaseItem ) If copy <> Null Local this : ItemB = ItemB( copy ) If this Self.x = this.x Self.y = this.y Return Self Endif Endif '// default init Self.x = 100 Self.y = 150 Return Self End Method End Class |
| ||
Found this and will have a read: http://msdn.microsoft.com/en-us/library/orm-9780596527730-01-05.aspx |
| ||
@AdamRedwoods: Yeah, I tried doing it with method overloading but alas it was rejected so had to cast the return value instead. |
| ||
@NoOdle Interesting idea. Seems like it could work! |