Let's say I have a class with some a couple properties:
public class MyClass {
public var fooProp:*;
public var barProp:Object;
}
What is the difference, practically speaking, between these? Are there variable types I can later assign to fooProp that I cannot assign to barProp?
Only untyped variables can hold the value undefined. Untyped variables are variables that either lack any type annotation, or use the asterisk * symbol for type annotation.
From ActionScript data type descriptors:
In previous versions of ActionScript, a variable with no type
annotation was automatically assigned the Object data type. This is no
longer true in ActionScript 3.0, which now includes the idea of a
truly untyped variable. Variables with no type annotation are now
considered untyped. If you prefer to make it clear to readers of your
code that your intention is to leave a variable untyped, you can use
the new asterisk (*) symbol for the type annotation, which is
equivalent to omitting a type annotation. The following example shows
two equivalent statements, both of which declare an untyped variable:
var x
var x:*
Only untyped variables can hold the value undefined. If you attempt to
assign the value undefined to a variable that has a data type, Flash
Player or Adobe AIR will convert the value undefined to the default
value of that data type. For instances of the Object data type, the
default value is null, which means that Flash Player or Adobe AIR will
convert the value undefined to null if you attempt to assign undefined
to an Object instance.
As an example:
var t:* = undefined;
trace(t); // outputs: undefined
var t:Object = undefined;
trace(t); // outputs: null
Related
I'm reading an android app and do not understand why the constructor in the ListeningQuestion.java uses this.variable = variable in its own constructor, but only variable = variable (no this) in the ListeningQuestionItem.java. They both have variable declared as private in the respective class. Why the differences? Any help?
The constructor as declared in ListeningQuestion.java you are looking -
public ListeningQuestion(String listeningFileID, String listeningSoundAddress, String listeningImageAddress,
ArrayList<ListeningQuestionItem> listeningQuestionItems) {
this.listeningFileID = listeningFileID;
this.listeningSoundAddress = listeningSoundAddress;
this.listeningImageAddress = listeningImageAddress;
this.listeningQuestionItems = listeningQuestionItems;
}
If we see the constructor, the name of the parameter is same as the name of private variable.
By specifying, this, I am explicitly asking to assign the value of parameter to the local variable. This signifies the instance to current class.
In case I do not use this keyword, the value will not be assigned to local private variable, but re assigned to the parameter value itself, because it has narrower scope.
It is a common convention to assign the parameter values to local variable this way.
Some stuff here and here about using this keyword
Now if you see the constructor of ListeningQuestionItem.java,
The names of parameters and local variable, differs by case. And because there is no ambiguity, you can assign the value to private variable, without using this, as -
ListeningQuestionID = listeningQuestionID
As per https://docs.oracle.com/javase/tutorial/java/javaOO
Within an instance method or a constructor, this is a reference to the current object — the object whose method or constructor is being called.
An object has state, and in case there are same local variables of same name as of the instance fields then fields can be accessed using this keyword.
this.listeningFileID = listeningFileID;
In this case there is one instance variable named as listeningFileID which is accessed using this and other is the local variable which is passed as a parameter to the constructor.
Java variable names are case senstive. In the second case
ListeningQuestionContent = listeningQuestionContent;
Observe the first character , the field name is ListeningQuestionContent and the local variable passed as parameter is named as listeningQuestionContent. Here we do not have same names so this js not used (although this is same as this.ListeningQuestionContent = listeningQuestionContent;)
I have a TActor class and a function to_bytes() inside it that should compress it to a bytes array as in this example: http://jacksondunstan.com/articles/1642
public function to_bytes():ByteArray
{
registerClassAlias("TActor",TActor);
var bytes:ByteArray=new ByteArray();
bytes.writeObject(this as TActor);
bytes.position=0;
trace(bytes.readObject());
bytes.position=0;
trace(bytes.readObject() as TActor);
return bytes;
}
However, the first trace prints undefined and the second one null instead of [object TActor].
What do I do wrong?
It's important to note that the this keyword returns the current instance of the object. What you are currently doing is attempting to pass the this instance to writeObject, which will only work if there is an instance of TActor instantiated. So it would work in this scenario:
In some class where you instantiate TActor:
var tactor:TActor = new TActor();
tactor.to_bytes();
Then it should serialize correctly.
Also as we discovered in the comments, TActor is of type MovieClip, currently you cannot use writeObject() on Objects of type MovieClip. More specifically any object that is a dynamic class cannot be used in writeObject. Changing it to Sprite solved this particular case.
Why is the valueOf() function present in everything in AS3? I can't think of an instance when this isn't redundant. In terms of getting a value, x and x.valueOf() are completely the same to me (except that one probably takes more CPU cycles). Furthermore even though they may not be the same in terms of setting something, x.valueOf() = y (if even legal) is just completely pointless.
I am confident though that this is here for a reason that I'm just not seeing. What is it? I did try Googling for a minute. Thanks!
As you say, its completely redundant.
The valueOf method is simply included so that ActionScript 3 complies with the ECMA language specification (obviously there are other requirements to be an ECMA language - i believe toString is another example).
Returns the primitive value of the specified object. If this object does not have a
primitive value, the object itself is returned.
Source: Adobe AS3 Reference http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Object.html#valueOf()
Edit:
A primitive value can be a Number, int, bool, etc... They are just the value. An object can have properties, methods, etc.
Biggest difference, in my opinion though:
primitive2 = primitive1;
In this example, primitive 2 contains a copy of the data in primitive 1.
obj2 = obj1;
In this one, however, ob2 points to the same object as obj1. Modify either obj1 or obj2 and they both reflect the change, since they are references.
In short, valueOf is used when you want to see the primitive representation of an object (if one exists) rather than the object itself.
Here is a clear example between
Value Vs. ValueOf:
Value = Thu Jan 2 13:46:51 GMT-0800 2014 (value is date formatted)
ValueOf = 1388699211000 (valueOf is in Raw epoch)
valueOf isn't useless. It allows an Object to provide a value for an expression that expects a primitive type. It's available in AS3 as well as JavaScript.
If someone wrote a function that takes an int, you could pass it your object (more precisely, it passes the result of your object's valueOf() function).
The usefulness is tempered by 1) the fact that the Object isn't passed, so it's only an Object in the outermost scope, and 2) the fact that it's a read-only operation, no assignment can be made.
Here're a couple concrete examples off the top of my head:
Example 1: A Counter class that automatically increments its value every time it's read:
class Counter
{
private var _cnt:int = 0;
public function Counter() { }
public function valueOf():int
{
return _cnt++;
}
public function toString():String { return ""+valueOf(); }
}
Usage:
var c:* = new Counter();
trace(c); // 0
trace(c); // 1
trace(2*c+c); // 2*2+3 = 7
trace(c); // 4
Notes:
I added the toString() pass-through, since functions that take String prefer toString over valueOf.
You must type c as * and not Counter, otherwise you'll get a compiler error about implicit coercion of Counter to Number.
Example 2: A (read only) pointer type
Let's say you have an array of ints, and you want to have a reference (aka pointer) to an element in the array. ECMA scripts don't have pointers, but you can emulate one with valueOf():
class ArrayIntPointer
{
private var arr:Array;
private var idx:int;
public function ArrayIntPointer(arr:Array,
idx:int)
{
this.arr = arr;
this.idx = idx;
}
public function valueOf():int
{
return arr[idx];
}
public function toString():String { return ""+valueOf(); }
}
Usage:
var arr:Array = [1, 2, 3, 4, 5];
var int_ptr:* = new ArrayIntPointer(arr, 2);
// int_ptr is a pointer to the third item in the array and
// can be used in place of an int thanks to valueOf()
trace(int_ptr); // 3
var val:int = 2*int_ptr+1;
trace(val); // 7
// but it's still an object with references, so I
// can change the underlying Array, nand now my
// object's primitive (aka, non-Object types) value
// is 50, and it still can be used in place of an int.
arr[2] = 50;
trace(int_ptr); // 50
// you can assign int_ptr, but sadly, this doesn't
// affect the array.
That's pretty slick. It'd be really slick if you could assign the pointer and affect the array, but unfortunately that's not possible, as it assigns the int_ptr variable instead. That's why I call it a read-only pointer.
var leaderboardRowVOs:Vector.<LeaderboardRowVO> = new Vector.<LeaderboardRowVO>();
goes to another part of the system as an Object, and I'm trying to cast it back to actual type
notification.getBody() as Vector.<LeaderboardRowVO> //throwing error
There are two ways of type casting in AS3:
// Casting
// 1: returns null if types are not compatible,
// returns reference otherwise
notification.getBody() as Vector.<LeaderboardRowVO>
// Converting
// 2: throws exception if types are not compatible,
// returns reference otherwise
Vector.<LeaderboardRowVO>(notification.getBody())
Case 1 does not throw error, if you have such a behaviour, there must be an error in notification.getBody() method.
EDIT: #divillysausages made a clever comment about case 2 actually creating an object of another type. This is not the case here. This is what mostly happens for native types with one exception: the Array class. Some of the native classes have top level converting functions. Refer to adobe livedocs for the complete list of them. A Vector can be instantiated this way by passing an Array of appropriate types to the Vector() function.
Something else must happen to the Vector within your class because it's valid to cast a vector to Object and then back to Vector. This simple test shows it:
var v:Vector.<int> = new Vector.<int>();
v.push(1);
v.push(2);
var o:Object = v as Object;
var v2:Vector.<int> = o as Vector.<int>;
trace(v2[0]); // Output "1"
trace(v2[1]); // Output "2"
So your problem must be somewhere else.
I am not sure if I am missing something here. I would like to compare two classes that uses the same interface. Is this possible? I understand that the is operator compares classes, but is there any similar function when you use interfaces?
// works
var effect1 : CrazyEffect = new CrazyEffect();
var effect2 : SaneEffect = new SaneEffect();
trace(effect1 is effect2) // false
// does not work
var effect1 : ISoundEffect = new CrazyEffect();
var effect2 : ISoundEffect = new SaneEffect();
trace(effect1 is effect2)
1067: Implicit coercion of a value of type ISoundEffect to an unrelated type Class.
Note the differences between concepts of a class and of an object. The former is a data type whereas the latter is a runtime instance of it, a variable. is operator can not compare one variable to another.
According to language reference
is Operator
Evaluates whether an object is compatible with a specific data type,
class, or interface. Use the is operator instead of the instanceof
operator for type comparisons. You can also use the is operator to
check whether an object implements an interface.
In other words, compiler expects the first operand to be a variable whereas the second operand should be a type identifier.
var sample:String = "Object is an instance of a class.";
^^^ ^^^
variable type identifier
However effect2 is not a type identifier but a variable. Hence the error message.
Unfortunately there is no generic operator to test for interface commonality. The only alternative is:
trace((s is ISoundEffect) && (t is ISoundEffect));
Update
Checking whether objects are instances of a same class can be done by comparing class names:
if (getQualifiedClassName(effect1) == getQualifiedClassName(effect2)) {
// true
}
For in depth discussion see Get the class used to create an object instance in AS3
Even though it will work with getQualifiedClassName, there's a better method to check whether two objects are instances of the same class:
a['constructor'] === b['constructor']
getQualifiedClassName is very slow and CPU intensive. Since the above code just compares property values it is lightning fast. And yes, constructor IS a property of every object, however FB will complain if you try to access it using dot-notation, that's why I use dynamic property access.