Implicit cast from Object?

Monkey Forums/Monkey Programming/Implicit cast from Object?

Nobuyuki(Posted 2013) [#1]
Can anyone talk to me about why we need to explicitly cast stuff from Object to the target object if a method outputting Object uses the same type as the resultant cast type? Cloning objects in a complicated system is kind-of a pain when things inherit say an iCloneable interface, if a required method Clone() returns Object. Just looking for a lesson in language mechanics, I guess. I would've figured that all objects inherit from Object and would thus not need to be explicitly cast back to something else, but I'm not sure exactly how it all works under the hood.


amando(Posted 2013) [#2]
I have this question too, I would really appreciate if someone can throw some light on this.

Thanks!
Amando


AdamRedwoods(Posted 2013) [#3]
Are you referring to this?

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
  Method CloneMe:A()
    Return New B
  End
End

Local b1:B = New B()
Local b2:B = B( b1.CloneMe ) ''needs a cast



Nobuyuki(Posted 2013) [#4]
Example

'Cloneable interface
Interface i
	Method Clone:Object()
End Interface

Class A Implements i
	Field f:Int = 1
	
	Method New(f:Int)
		Self.f = f
	End Method
	
	Method Clone:Object()
		Return New A(f)
	End Method
End Class

Function Main:Int()
	Local my_A:A = New A(1234)
	
	Local my_A_copy:A = A(my_A.Clone())         'OK - Explicitly cast to A
	Local my_implicit_A_copy:A = my_A.Clone()   'NG - "can't convert Object to A"
End Function


Implicit inheritance from Object would make coding modules with a lot of classes implementing an Interface easier, because it would keep variables agnostic (for example) to the interface type instead of requiring explicit cast. I'd assumed that explicit cast wouldn't be necessary, believing all objects extend Object...


marksibly(Posted 2013) [#5]
This is true of pretty much all statically typed languages I know of - eg: none of C#, Java, C++ will implicitly cast from 'object' to a derived class.

There's not really any technical reason it can't be done, but to me it's not really that different from allowing implicit downcasting from any class to any class - the basic danger is still that an object is not of the class you logically expect it to be, ie: (Derived(obj)=Null)<>(obj=Null) so I think it's best to suffer the downcasting to 'remind' you to be careful.

Of course, in some situations like the above it's obvious that it will work fine, but it doesn't take much extra code for things to start looking much less clear cut.

Some of this is due to lack of 'covariant return types' in Monkey - see: http://en.wikipedia.org/wiki/Covariant_return_type - a feature most OO languages have (even bmx!) EXCEPT for C# (and possibly as3) for some strange reason.

But hey, convince me this is a good idea!


AdamRedwoods(Posted 2013) [#6]
EXCEPT for C# (and possibly as3) for some strange reason.

ahhhh... that's the language to spoil it for everyone else!

I'd love to see covariant return types, I even thought that perhaps monkey could auto-detect and auto-cast for us. That wouldn't disrupt any current code, but my only concern: does it break any static typing rules?
If not, +1


Nobuyuki(Posted 2013) [#7]
thanks for the info :)

I'm also gonna say it would be useful to have something to address this, although not absolutely necessary (and I'm not sure how it would be properly implemented, either). This page here illustrates a similar problem, which is solved in a way Monkey doesn't support (subclass overriding/overloading the base class with a different method signature): http://blog.chrishowie.com/2013/01/22/object-copying-in-c/

In VB.NET, neither problem exists afaik, although I couldn't say why, specifically -- iirc, type narrowing conventions with cloning "just work" and there exist both Overrides and Overloads keywords for methods which allow explicitly for subclasses to override or overload a method, respectively.


Grey Alien(Posted 2013) [#8]
Yeah I'd like to see subclass method overriding too as that would solve the cloning problem without resorting to casting or having to use factory classes.


amando(Posted 2013) [#9]
+1. Mark, I wish these posts are enough to convince you ;)


Samah(Posted 2013) [#10]
-1 to this.
One of the points of inheritance is to ensure that if your program compiles and you are NOT using any explicit casts, it is type safe and will not give you any nasty class cast errors.

Let me give you another example then:
[monkeycode]Class Foo
End
Class Bar
End

Function Main()
Local hello:Object = New Foo ' compiles and runs fine, because Foo extends Object
Local explicit:Bar = Bar(hello) ' compiles fine, but fails at runtime, because hello is a Foo, not a Bar <-- not type safe
Local currentImplicit:Bar = hello ' does not compile, because the compiler cannot guarantee that hello is a Bar
Local yourImplicit:Bar = hello ' would compile as per your suggestion, but would fail at runtime, because hello is a Foo, not a Bar <-- not type safe
End[/monkeycode]

Just because part of an expression is of type "Object" doesn't mean the value is. Adding this functionality could break all sorts of things.

Edit: By your own code example, add another class B that does the same thing as A:
[monkeycode]Class B Implements i
Field f:Int = 1

Method New(f:Int)
Self.f = f
End Method

Method Clone:Object()
Return New B(f)
End Method
End Class

Function Main:Int()
Local my_A:B = New B(1234)
Local my_implicit_A_copy:A = my_A.Clone() ' compiles but fails at runtime
End Function[/monkeycode]


muddy_shoes(Posted 2013) [#11]
Local explicit:Bar = Bar(hello) ' compiles fine, but fails at runtime, because hello is a Foo, not a Bar <-- not type safe


Except that doesn't fail at runtime because Monkey spits a Null out of an illegal cast. Presumably an implicit cast would do the same.


Samah(Posted 2013) [#12]
@muddy_shoes: Except that doesn't fail at runtime

If you're expecting hello to be a non-null value of type Bar, then your program logic is failing at runtime. Note that I didn't say "exception". The difference is that casting in Monkey is also a shorthand for Java's "instanceof" or C#'s "is".


muddy_shoes(Posted 2013) [#13]
By your logic the implicit and explicit casts are both runtime failures. You're not demonstrating any difference in behaviour.


Samah(Posted 2013) [#14]
@muddy_shoes: By your logic the explicit cast is also a runtime failure

One of the points of inheritance is to ensure that if your program compiles and you are NOT using any explicit casts, it is type safe and will not give you any nasty class cast errors.

Type safety is (supposed to be) guaranteed if you aren't forcing the cast. If you ARE forcing the cast, the compiler assumes you know what you're doing. That said, it will still fail compilation if the compiler sees that what you're doing is technically impossible (casting a String to a List, etc.)


muddy_shoes(Posted 2013) [#15]
What something is "supposed to" do in other languages doesn't mean much in the Monkey world. In the circumstances people are talking about they're just bugged by having to explicitly tell the compiler they're willing to risk a failed cast.

I wouldn't want this feature myself but I can see it fitting into the soup of the Non-Strict mode.


Samah(Posted 2013) [#16]
@muddy_shoes: ...but I can see it fitting into the soup of the Non-Strict mode.

I'll agree with you here, because to be honest I think Strict should be default, and replaced with an optional "LazyBastardMode" keyword. :D


ziggy(Posted 2013) [#17]
but samah, isn't your example a contravariance example instead of a covariance example?

By the way, it seems that C# supports covariance and contravariance on generics http://msdn.microsoft.com/en-us/library/dd799517.aspx since version 4

I would opt for standar overriding covariance where an overriding method can return a derived class instance from the overriden class (but not the opposite)


Nobuyuki(Posted 2013) [#18]
as a lazy bastard, one of the reasons I was asking about this was because I didn't want to have to think about the consequences of Clone interface inheritance (I don't in my native programming language!) and copy constructors didn't seem to be the correct fit for my particular usage pattern.

But, in any case, explicitly casting doesn't seem to be required in any of my base classes, so far, so really this was a bit of a non-issue for me, and just a general question about language design.