How to define enum in as3? - actionscript-3

Is there a way to define an enum in AS3 in a way we do it in other languages? I can define constants with defined values like that:
private const CONST_1:int = 0;
private const CONST_2:int = 1;
private const CONST_3:int = 2;
and so on. If I want to insert some other constant between 3 these I need to move all values like that:
private const CONST_1:int = 0;
private const CONST_2:int = 1;
private const CONST_2A:int = 2;
private const CONST_3:int = 3;
while in other language I would end up with only adding a new member to enum closure like that:
enum {
CONST_1 = 0,
CONST_2,
CONST_2A,
CONST_3
} MyConstEnum;
Does AS3 has something similar?
Thanks

No AS3 doesn't have enum, you have to code them yourself. You can simulate them for example by a class if you want safer type checking.

public static var NUM_ENUM_VALUES:int = 0;
public static const EV_MONDAY:int = NUM_ENUM_VALUES++;
public static const EV_TUESDAY:int = NUM_ENUM_VALUES++;
public static const EV_WEDNESDAY:int = NUM_ENUM_VALUES++;
public static const EV_THURSDAY:int = NUM_ENUM_VALUES++;

You can take a look at the variety of variable types supported by the ActionScript Virtual Machine. Variable types are annotated by traits, the variety of which can be found in the specification, table 4.8.1:
4.8.1 Summary of trait types
The following table summarizes the trait types.
Type Value
Trait_Slot 0
Trait_Method 1
Trait_Getter 2
Trait_Setter 3
Trait_Class 4
Trait_Function 5
Trait_Const 6
There is no Trait_Enum and note that under Trait_Const description, only constants from the constant pool are allowed, so that would be:
signed integers
unsigned integers
doubles
strings
type names and vector types
Enums could be made of signed or unsigned integers, for example, but the virtual machine would not perform any type-safety checking of the operations which used those types. (E.g., the getlocal or coerce opcodes used would be getlocal_i and coerce_i, respectively.)
The ABC format doesn't have any built-in provision for enum types that I know of.
Using an object type for each enum value could work, especially if the compiler emits coerce instructions for that type prior to uses of getlocal and otherwise doesn't use the object other than in istype and astype variants. For example, calling setproperty or getproperty on the object would be slower than using an integer -- especially if that property is bound to a getter or setter method.
There are replacement styles which have been linked in other answers. To evaluate the runtime performance impact of these styles, you can uses swfdump -D from the swftoools open-source Flash tools collection.

Related

Convert an instance of QObject to JSON

I have some code that I am using to convert arbitrary QObject subclasses to JSON. I able to convert them if they are pointers to a subclass, but am curious whether it is possible to convert instances (provided the subclass implements a copy constructor). Is there some crazy way to use something like templates or the type information provided by QMetaType to copy an instance of a QObject subclass without knowing what it is? The ToJson code is in a class that has no knowledge of the subclass.
I think it might be possible with QMetaType::create or something similar but I haven't been able to figure out how to actually copy the properties of the subclass instance.
Here's my code for converting:
QJsonValue ToJson(QVariant value){
switch(value.type()){
case QVariant::Int:
case QVariant::Double:
return value.toDouble();
////Other cases, etc...
case QVariant::UserType:
QObject* obj_ptr = qvariant_cast<QObject*>(value);
if(obj_ptr) // value was originally a pointer to a QObject, works correctly
return ToJson(obj_ptr);
else { // value was orginally an instance of a QObject subclass
std::string t = value.typeName(); //returns "MyQObject"
int id = QMetaType::type(t.c_str()); //returns the id of the derived class
void* v = QMetaType::create(id, &value); //passing &value does nothing
obj_ptr = static_cast<QObject*>(v);
return ToJson(obj_ptr); //works, but resulting fields are all default
}
}
}
QJsonObject ToJson(QObject* o){
QJsonObject obj;
auto mo = o->metaObject();
for (int i = mo->propertyOffset(); i < mo->propertyCount(); ++i){
QVariant value = o->property(mo->property(i).name());
obj[mo->property(i).name()] = ToJson(value);
}
return obj;
}
Sample code use case:
qRegisterMetaType<MyQObject>();
MyQObject obj;
obj.db = 11.1;
QVariant test1 = QVariant::fromValue(obj);
QVariant test2 = QVariant::fromValue(&obj);
QJsonValue v1 = ToJson(test1); // default constructed values
QJsonValue v2 = ToJson(test2); // db = 11.1
Sample QObject subclass:
class MyQObject : public QObject {
Q_OBJECT
Q_PROPERTY(double DB MEMBER db)
Q_PROPERTY(int I MEMBER i)
public:
MyQObject();
MyQObject(const MyQObject& other) : QObject() {
i = other.i;
db = other.db;
}
int i = 50;
double db = 1.5;
};
Q_DECLARE_METATYPE(MyQObject)
Is there any way to handle the case illustrated by test1 above?
Long-story-short: nope. There is no way to store QObjects by value in containers or QVariant.
Qt forbids the copy of QObjects and all inheriting classes. The mandatory the Q_OBJECT macro will disable any copy constructor also in newly defined classes.
The copy constructor that you are defining in the MyObject class is missing the base class constructor call. If QObject had a copy constructor it would be something like this:
MyQObject(const MyQObject& other) :
QObject(other) // this will NEVER compile
{
i = other.i;
db = other.db;
}
Probably, the compiler is giving you a warning, but allows you to have such a constructor, even if it will result in undefined behavior or slicing an instance of MyObject every time it is passed by value.
Furthermore, the Qt docs states the following:
The values stored in the various containers can be of any assignable
data type. To qualify, a type must provide a default constructor, a
copy constructor, and an assignment operator. This covers most data
types you are likely to want to store in a container, including basic
types such as int and double, pointer types, and Qt data types such as
QString, QDate, and QTime, but it doesn't cover QObject or any QObject
subclass (QWidget, QDialog, QTimer, etc.).
So you can't store QObject and derived classes inside a Qt container unless you store them as pointers, as copy of QObjects is disabled by design.
Furthermore, if you want to exploit polymorphic behavior you must use pointers, even if there is no explicit need to cast to derived classes in your code, as far as I can see. If you really need to resort to casting in some place, you could consider making your ToJson a template function.
There is a solution, but use caution as it is only reasonable/applicable in the following scenario:
Classes in question are primarily data storage classes
The classes in question would be entirely copy-able if they didn't inherit from QObject
Most importantly, the ONLY reason you have the class inherit from QObject is so that it can have meta properties.
If your code uses the class as a QObject for any reason other than to get meta information, you are almost certainly using it incorrectly if you are trying to store it by value (as explained by G. Giordano in their answer).
Misuse considerations aside, in order to JSON-ify a QVariant that stores a QObject subclass by value, you can use the QMetaType::create method and pass it the user type id and yourQVariant.constData().
Example:
MyQObject obj;
obj.db = 11.1;
QVariant value = QVariant::fromValue(obj);
std::string t = value.typeName();
int id = QMetaType::type(t.c_str());
void* v = QMetaType::create(id, value.constData());
obj_ptr = static_cast<QObject*>(v);
QJsonValue json = ToJson(obj_ptr); //json contains db = 11.1

What is the use in having the valueOf() function?

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.

List of OO languages where object immutability can be compiler enforced

Can anyone give me a list of languages where class immutability can be compiler enforced and tested easily ?
I need to be able to do something like:
class immutable Person {
private String name = "Jhon"; // lets say the String is mutable
public Person(String name) {
this.name = name; // ok
}
public void setName(String newName) {
this.name = newName; // does not compile
}
public void getName() {
return this.name; //returns reference through which name can't be mutated
}
private void testImmutability() {
getName().setFirstChar('a'); // does not compile
}
}
EDIT:
For a little more clarification, see here.
Functional programming languages like OCAML, Haskell, and Erlang.
F# and Scala both have the ability to created compiler-enforced immutable types (i.e. classes).
The following shows the basics in F#...
// using records is the easiest approach (but there are others)
type Person = { Name:string; Age:int; }
let p = { Person.Name="Paul";Age=31; }
// the next line throws a compiler error
p.Name <- "Paulmichael"
Here's the equivalent Scala. Note that you can still make mutable objects by using var instead of val.
class Person(val name: String, val age: Int)
val p = new Person("Paul", 31)
// the next line throws a compiler error
p.name = "Paulmichael"
Joe-E
From the language spec
3.4 Immutable Types
A type T is immutable if and only if it implements
the marker interface org.joe_e.Immutable according to the overlay
type system. The (empty) org.joe_e.Immutable interface must be provided
by the Joe-E implementation. The
intuition behind an immutable object
is that such an object cannot be
changed (mutated) in any observable
way, nor can any objects reachable by
following the elds of the immutable
object. The contents of an immutable
objects' elds and any objects
reachable from an immutable object
must not change once the object is
constructed. With the exception of
library classes explicitly deemed to
implement Immutable, an immutable
class must satisfy additional
linguistic restrictions enforced by
the verier (x4.4) to ensure this
property. Library classes that cannot
be automatically verified and are
deemed immutable must be carefully
manually veried to expose no
possibility for modication of their
contents. Note that immutability does
not place any restrictions on any
local variables dened within the
immutable class. It also says nothing
about the mutability of the arguments
passed to methods. It only applies to
the values stored in and objects
reachable from the immutable class's
elds
It also introduces useful notions of powerless, and selfless types.
The D (version D2) programming language has immutability. It has OOP, but immutability is rather a concept from functional pl. There it's called purity.

User-defined type conversions in ActionScript?

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.

Creating a "true" HashMap implementation with Object Equality in ActionScript 3

I've been spending some of my spare time working a set of collections for ActionScript 3 but I've hit a pretty serious roadblock thanks for the way ActionScript 3 handles equality checks inside Dictionary Objects.
When you compare a key in a dictionary, ActionScript uses the === operator to perform the comparison, this has a bit of a nasty side effect whereby only references to the same instance will resolve true and not objects of equality. Here's what I mean:
const jonny1 : Person = new Person("jonny", 26);
const jonny2 : Person = new Person("jonny", 26);
const table : Dictionary = new Dictionary();
table[jonny1] = "That's me";
trace(table[jonny1]) // traces: "That's me"
trace(table[jonny2]) // traces: undefined.
The way I am attempting to combat this is to provide an Equalizer interface which looks like this:
public interface Equalizer
{
function equals(object : Object) : Boolean;
}
This allows to to perform an instanceOf-esq. check whenever I need to perform an equality operation inside my collections (falling back on the === operator when the object doesn't implement Equalizer); however, this doesn't get around the fact that my underlying datastructure (the Dictionary Object) has no knowledge of this.
The way I am currently working around the issue is by iterating through all the keys in the dictionary and performing the equality check whenever I perform a containsKey() or get() operation - however, this pretty much defeats the entire point of a hashmap (cheap lookup operations).
If I am unable to continue using a Dictionary instance as the backing for map, how would I go about creating the hashes for unique object instances passed in as keys so I can still maintain equality?
How about you compute a hash code for your objects when you insert them, and then look them up by the hash code in your backing dictionary? The hashcode should compare === just fine. Of course, that would require you to have a Hashable interface for your object types instead of your Equalizer interface, so it isn't much less work than you are already doing, but you do get the cheap lookups.
How about rather doing this:
public interface Hashable {
function hash():String;
}
personally, I ask myself, why you want to do this ... hashing objects to obtain keys makes little sense if they are mutable ...
also, you might consider using a different approach, as for example this factory:
package {
public class Person {
/**
* don't use this!
* #private
*/
public function Person(name:String, age:int) {
if (!instantiationAllowed)
throw new Error("use Person.getPerson instead of constructor");
//...
}
private static var instantiationAllowed:Boolean = false;
private static var map:Object = {};
private static function create(name:String, age:int):Person {
instantiationAllowed = true;
var ret:Person = new Person(name, age);
instantiationAllowed = false;
}
public static function getPerson(name:String, age:int):Person {
var ageMap:Array = map[name];
if (ageMap == null) {
map[name] = ageMap = [];
return ageMap[age] = Person.create(name, age);
}
if (ageMap.hasOwnProperty(age))
return ageMap[age];
return ageMap[age] = Person.create(name, age);
}
}
}
it ensures, there's only one person with a given name and age (if that makes any sense) ...
Old thread I know, but still worth posting.
const jonny1 : Person = new Person("jonny", 26); const jonny2 : Person = new Person("jonny", 26);
is creating two completely different objects that will not compare using ==, guess I don't see why it's any more of a road block because of as3
The problem with AS3/JavaScript/EcmaScript is not that they create two different, equivalent objects.
The problem is that they cannot equate those two equivalent objects--only identity works, since there is no equals or hashCode methods that can be overriden with class-specific comparison logic.
For Map implementations such as dynamic Object or Dictionary, this means that you have to either use Strings or references as keys: you cannot recover objects from a map using different but equivalent objects.
To work around that problem, people either resort to strict toString implementations (for Object maps) which is undesirable, or to instance control for Dictionaries, as in #back2dos example, which introduces different problems (Also, note that #back2dos solution does not really guarantee unique Person instances since there is a time window during which asynchronous threads will be allowed to instantiate new Persons).
#A.Levy's solution is good except that in general, hashCodes are not strictly required to issue unique values (they are meant to map entries to buckets allowing for fast lookups, wherein fine-grained differentiation is done through equals method).
You need both a hashCode and an equals method, e.g.
public interface IEquable
{
function equals(object : Object) : Boolean;
function hash():String;
}
In any programming language,
const jonny1 : Person = new Person("jonny", 26);
const jonny2 : Person = new Person("jonny", 26);
is creating two completely different objects that will not compare using ==, guess I don't see why it's any more of a road block because of as3