In languages like Java, C++ and etc there is the ability to provide, for example, a toInt() function to allow your code to be converted neatly by language features into a given primitive type. (In this example, an Int.)
That is, if you had myObject() with the standard casting function toInt() declared, then calls like Int(myObject) would just work. This is much more relevant to situations where you just want to forget about the cast altogether and just get something done - someVar:Int = myObject + 3 ... for an arbitrary example.
I've searched through AS3 docs and done some searching outside that but it appears there is no such sets of functions, interfaces, or other such things easily accessible in AS3. Does anyone know such a thing? It seems like essential knowledge in any language that supports such casting features and I'm at my wit's end with the verbosity of writing a partially qualified name like myObject.toInt() in the midst of mathematical work.
It's a common misconception that operator overloading in AS3 is impossible. It's not, but it's not entirely common practice, and it doesn't work as in other languages.
AS3 is "gradually typed". This means that you can specify type when you want to, you don't have to, and when performing operations on two different types it'll infer/cast for you in a logical way.
For objects, AS3 provides the valueOf():Object and toString():String functions which allow you to define the automatic handling of casting. The former provides the "primitive value of the object" while the latter defines the "String representation of the Object".
The default value for both is the String "[object ClassName]", but you can override this default. Here's an example:
package
{
import flash.display.Sprite;
import flash.utils.getQualifiedClassName;
public class Main extends Sprite
{
public function Main():void
{
trace("-----------------------------");
var foo = new MyClass();
trace("foo is: ");
trace(foo);
trace("foo+foo is:");
trace(foo+foo);
trace("foo+foo+'--' is:");
trace(foo+foo+"--");
trace("'--'+foo+foo is:");
trace("--"+foo+foo);
trace("Math.PI/foo:");
trace(Math.PI/foo);
trace("'5'+foo is:");
trace('5'+foo);
trace("false || foo is:");
trace((false || foo));
trace("foo | 0xC is:");
trace(foo | 0xC);
trace("typeof(foo) is:");
trace(typeof(foo));
trace("getQualifiedClassName(foo) is:");
trace(getQualifiedClassName(foo));
}
}
}
class MyClass {
public function valueOf():Object { return 3; }
public function toString():String { return "three"; }
}
And the trace output is:
-----------------------------
foo is:
three
foo+foo is:
6
foo+foo+'--' is:
6--
'--'+foo+foo is:
--threethree
Math.PI/foo:
1.0471975511965976
'5'+foo is:
5three
false || foo is:
three
foo | 0xC is:
15
typeof(foo) is:
object
getQualifiedClassName(foo) is:
Main.as$30::MyClass
The Boolean interpretation is interesting, but any non-null Object (or String) is true, so actually it works out. Whether the runtime calls valueOf() or toString() appears to be dependent on the types of the other arguments to the operators.
Related
The following trivial Kotlin code snippet
fun main() {}
compiles just fine, but the following
val main : () -> Unit = {}
makes the compiler complain that "No main method found in project.", while I was expecting them to be equivalent (I expect a programming language to be as conceptually uniform as possible).
Why does this happen? Is it related only to main, or does this behaviour concern a larger class of functions? Is there some subtle difference between declaring functions with "fun" and declaring them as lambdas?
Conceptually, they are different things. To see that, let's take a look at roughly what the equivalent Java would be. I'll use JVM for examples in this answer, but the same principles apply to all of the other Kotlin backends.
object Foo {
fun main() { ... }
}
This is roughly
class Foo {
public static void main() { ... }
}
Again, roughly. Technically, you'll get a singleton object and a method on it unless you use #JvmStatic (I assume there's some special handling for main that produces a static function on JVM, but I don't know that for a fact)
On the other hand,
object Foo {
val main: () -> Unit = { ... }
}
Here, we're declaring a property, which in Java is going to get implemented as a getter-setter pair
class Foo {
// Singleton instance
public static Foo instance = new Foo();
public Supplier<Void> main;
Foo() {
main = new Supplier<Void>() {
Void get() {
...
}
}
}
}
That is, there isn't actually a main method. There's a main field which, deep down somewhere, has a function inside of it. In my example above, that function is called get. In Kotlin, it's called invoke.
The way I like to think of it is this. Methods in Kotlin (i.e. the things you define on objects that designate their behavior) are not themselves first-class objects. They're second-class citizens which exist on an object. You can convert them to first-class objects by making them into functions. Functions are ordinary objects, like any other. If you take an ordinary object, which may or may not be a function, and call it with (), then you're actually invoking the method .invoke(...) on it. That is, () is an operator on objects which really ends up calling a method. So in Kotlin, functions are really just objects with a custom invoke and a lot of syntax sugar.
Your val defines a field which is a function. Your fun defines a method. Both of these can be called with (), but only one is a genuine method call; the other is secretly calling .invoke on another object. The fact that they look syntactically the same is irrelevant.
As the old adage goes, functions are a poor man's objects, and objects are a poor man's functions.
There is a subtle (or more than subtle) difference. Declaring it with val means that main is a property containing a reference to an anonymous function (which you defined with the lambda). If you define it with val, then when you call main(), you are actually calling the getter of the main property, and then using the invoke() operator to call invoke() on the return value of the property (the anonymous function).
I am designing a simple game in Flash and have come across this error. I have no idea how to go about this in actionscript and would appreciate any help.
Basically, I have a switch statement which creates an object of different type depending on each case (as I would prefer not to duplicate the same ten lines of code for each case) and I am getting a "conflict exists with definition in namespace internal" compiler error and I think I understand why.
switch(power){
case 1:
var Pow:objectOne = new objectOne();
break;
case 2:
var Pow:objectTwo = new objectTwo();
break;
}
My question however is this - what is the proper way of going about this?
I initially thought of declaring the variable before the switch statement which results in an "implicit coercion of a value of type object(One/Two) to an unrelated type Class" error. What am I missing here?
Aside from the compiler error you are experiencing, another problem here is that you are planning on using the pow variable later in your code, yet they are of different types. My suggestion is to use the benefits of Inheritance in OOP and create a base class that your two custom classes can inherit from. That way they are both technically of the same base type, while still giving you the freedom to customize each custom class, while keeping similar functionality in the base class.
Remember, OOP is here to always help you and is there to avoid issues like the one you have come across, but here is how I would do it, and I tested the following implementation in Flash CC 2014 and it compiled successfully:
Example .FLA:
var pow:BaseClass;
var power = 1;
switch(power){
case 1:
pow = new ObjectOne();
break;
case 2:
pow = new ObjectTwo();
break;
}
pow.whichObjectAmI(); // this will simply trace what object pow is
Base Class
package {
public class BaseClass {
public function BaseClass() {
// constructor code
}
public function whichObjectAmI() {
trace("I am the base class");
}
}
}
Object One
package {
public class ObjectOne extends BaseClass {
public function ObjectOne() {
// constructor code
}
override public function whichObjectAmI() {
trace("I am Object One!");
}
}
}
Object Two
package {
public class ObjectTwo extends BaseClass {
public function ObjectTwo() {
// constructor code
}
override public function whichObjectAmI() {
trace("I am Object Two!");
}
}
}
You can always inherit from any of ActionScript's classes as well like MovieClip, Button, etc. And by doing so, you're adding custom functionality on top of their functionality so 1) you don't have to rebuild a bunch of functionality, and 2) giving you the chance to reuse their functionality while adding your own custom code!
Disclaimer: My AS3 is a little rusty ;)
Of what type would the variable Pow be after the switch statement? objectOne or objectTwo? From the compiler's perspective objectOne and objectTwo could be totally different from each other (read: methods, fields,...)
So:
A) Keep variable name for both assignments but declare it before the switch-statement AND use a common base-type (object, MovieClip,...)
B) Have 2 different variables: var PowOne: objectOne and var PowTwo: objectTwo
I think option A would be preferable...
I am trying to develop a method in actionscript that takes a Class object as a parameter and will generate an instance of that class at runtime:
public function getComponent(componentType:Class):Object
{
return new componentType();
}
In some cases I may be passed a Class object that represents an interface instead. Naturally I cannot directly create an instance of an interface.
Is there some way to query the Class object and determine whether or not it represents an interface so that I can avoid trying to create an instance in this way?
Assume you follow a naming convention for your interface class, as in the standard IInterfaceName, name of the interface prefixed with a capital "I" following a capital letter and the rest of the class name. There are a couple of ways to do this. If you have a lot of different interfaces that could be passed as a parameter you could do this:
First import the flash.utils.getQualifiedClassName and in your function:
public function getComponent(componentType:Class):Object
{
var name:String = getQualifiedClassName( componentType ).replace(/.*\:+/g,"");
if ( name.search( /^\I[A-Z]/g ) != -1 ) {
trace( "parameter is an interface!" );
return null;
}
return new componentType();
}
You don't have to set the name variable, but this helps make the search a little more strict. You could just do this instead:
if ( getQualifiedClassName( componentType ).search( /\I[A-Z]/g ) != -1 ) {
trace( "parameter is an interface!" );
return null;
}
If you are not already aware, getQualifiedClassName returns the string format of the class name. The regular expressions check specifically for the capital IInterfaceName styled string.
Lastly, if you know it's only one interface, you could simple just do this:
if ( componentType == IMyinterface ) {
trace( "component is a IMyinterface" );
}
After some careful trial and error, I've come up with the following function:
public static function isInterface(clazz:Class):Boolean
{
return describeType(clazz).factory.extendsClass.(#type=="Object").length()==0;
}
Does anyone know if this condition always holds true for all actionscript interfaces?
I think this will work for you:
getQualifiedSuperclassName(classObject);
This will return null if you pass an interface, as interfaces does not have a superclass. It will always give you ANY kind of result for a class, as every class is basically an Object :)
Anyway, I don't think that passing such mixed values to a function is a good idea ;) And checking if the class starts with "I" is worse (sorry Bennett :))
p.s.
Keep in mind that describeType is EXTREMELY slow!
I'm designing a framework and in the process I have come across an interesting but most likely basic problem. I have a base class called CoreEngine and two other classes that extend it: CoreEngine1 and CoreEngine2. I created an interface that each of these classes would implement to increase the flexibility of my project. However, I have a problem... The definition of my methods in the interface do not match the definition in each inherited class! Each class must implement the following method:
function get avatar():AvatarBase;
The problem is that CoreEngine1 and CoreEngine2 expect a different type of avatar:
CoreEngine1
function get avatar():AvatarScaling
CoreEngine2
function get avatar():AvatarPlatform
As you can see, the return type for avatar in CoreEngine1 and CoreEngine2 do NOT match the type as specified in the interface. I was hoping that since both AvatarScaling and AvatarPlatform inherit AvatarBase that I wouldn't have a problem compiling. However, this is not the case. According to Adobe's documentation, the types MUST match the interface. I am trying to follow one of the core concepts of object oriented programming to extend the flexibility of my framework: "Program to an interface rather than an implementation". The first thing that comes to my mind is that the return type of the accessor method should be of an interface type (Maybe I just answered my own question).
I'm certain this is a common problem others have run into before. Architecturally, what do you think is the best way to solve this problem? Thanks in advance!
Regards,
Will
This is a limitation of how interfaces work and are declared.
If there's inheritance that can happen with the return types, as you've described with AvatarBase and subclasses, then I think the right approach is to make the return type the lowest common denominator and just handle the resulting object on the other end. So, if you're dealing with a CoreEngine1 object, you know you can cast the result from AvatarBase to AvatarScaling. Alternately, if you don't know the object type that you are calling get avatar() on, then you can type check the returned value. The type check would then only be needed if you're looking to call a method that exists on AvatarScaling but not on AvatarBase. I don't think returning an interface type will buy you much in this case because the only things that interface can implement would be things that all forms of Avatar share, which wouldn't be any different than methods in AvatarBase.
Like HotN and Dinko mentioned, it would be best to allow get avatar() to return AvatarBase allways and then cast the returned object as the concrete subclass.
Using Dinko's example:
public /* abstract */ class CoreEngine
{
public /* abstract */ function get avatar():AvatarBase {}
}
public function CoreEngine1 extends CoreEngine
{
override public function get avatar():AvatarBase { return new AvatarScaling(); }
}
public function CoreEngine2 extends CoreEngine
{
override public function get avatar():AvatarBase { return new AvatarPlatform(); }
}
public /* abstract */ class AvatarBase {}
public class AvatarScaling extends AvatarBase
{
public function someAvatarScalingMethod():void {}
}
public class AvatarPlatform extends AvatarBase
{
public function someAvatarPlatformMethod():void {}
}
To use a method from AvatarScaling, cast the returned object:
var c1:CoreEngine1 = new CoreEngine1();
var avatarScaling:AvatarScaling = AvatarScaling(c1.avatar());
avatarScaling.someAvatarScalingMethod();
hth
I think you answered your own question... the return type would still be AvatarBase, you need to follow the signature that you specified in the interface... but you can technically return ANY descendent of AvatarBase in that function. So doing something like
return new AvatarScaling();
in CoreEngine1 would be perfectly acceptable.
Of course in your calling function you will get back an AvatarBase instance, and you will have to know what this is in order to cast to a specific subclass.
CoreEngine1 ce1 = new CoreEngine1();
AvatarScaling avatar = ce1.avatar() as AvatarScaling;
Is there any way for me to define implicit or explicit type conversions in ActionScript?
For instance, I want to define a conversion such that Array can cast into MyClass implicitly. If not, an explicit cast would be useful. I know I can always pass it into my constructor, but I am dealing with semantics here, and I am most interested in a conversion solution if it exists.
Type casting in ActionScript 3
Object(instanceOfOtherObject);
Works based on the valueOf property of the given class (if defined). Therefore, you can define your class MyClass as such:
package {
public class MyClass {
private var myArray:Array;
public function MyClass(inputArray:Array = null) {
myArray = (inputArray ? inputArray : new Array());
}
public function valueOf():Array {
return myArray;
}
}
}
Then you will be able to perform this typecasting:
var mc:myClass = new MyClass();
var arr:Array = Array(myClass);
To my knowledge, the reverse is not an option because the valueOf function of Array does not return an object of type MyClass. There is nothing stopping you from creating a CastableArray that extends and overrides the valueOf function of Array to make it return an instance of MyClass using the constructor I defined above, though you may run into other issues with other fundamental language components that expect an Array to return an Array in its valueOf property (comparison of objects comes to mind).
I have not done any particular testing with this next suggestion, but if MyClass extends from Array and does not define a valueOf function, it may still be possible to do the type conversion depending on the constructor of MyClass and what Flash does in circumstances when valueOf is not defined.