AS3 httpservice - pass arguments to event handlers by reference - actionscript-3

I have this code:
var service:HTTPService = new HTTPService();
if (search.Location && search.Location.length > 0 && chkLocalSearch.selected) {
service.url = 'http://ajax.googleapis.com/ajax/services/search/local';
service.request.q = search.Keyword;
service.request.near = search.Location;
} else
{
service.url = 'http://ajax.googleapis.com/ajax/services/search/web';
service.request.q = search.Keyword + " " + search.Location;
}
service.request.v = '1.0';
service.resultFormat = 'text';
service.addEventListener(ResultEvent.RESULT, onServerResponse);
service.send();
I want to pass the search object to the result method (onServerResponse), but if I do it in a closure it gets passed by value. Is there a way to do it by reference without searching through my array of search objects for the value returned in the result?

I'm not quite sure what you want to do here.
Parameters are indeed passed by value. In the case of objects (and by object here I mean everything that has reference semantics, i.e. everything but Booleans, Number, ints, Strings, etc), a reference to them is passed by value, so in your function you have a reference to the original object, not a reference to a copy of the object.
So, if you want to dereference the object and change some value or call some method on it, you'll be ok. The only thing that wont work is changing the reference itself; i.e. you can't null it out or assign a new object to it:
function dereferenceParam(param:Object):void {
param.someInt = 4;
param.someMethod();
}
function reassignParam(param:Object):void {
param = null;
// or
param = new Object();
}
dereferenceParam() will work as most people expect, reassignParam won't.
Now, the only possible "problem" I think you could have as per your last paragraph would be that you want to remove or null out the search object from some array you have. I'm afraid in that case, the only way would be to loop through the array.

How are you determining that you have received a copy of the object?
To my knowledge, (non-intrinsic) objects are almost never copied by value. The only exception are dispatched Event objects, but that is explicitly documented.

Related

How to test whether a class instance is a dynamic type in AS3?

In AS3, if a class is marked as dynamic, new properties can be added and removed at runtime, by simply setting the property or removing it with the delete keyword.
I am asking whether there is a faster way to determine whether a class is dynamic than calling the describeType function and checking the "isDynamic" attribute value on the returned top-level XML node, for example: <type name="flash.display::MovieClip" base="Class" isDynamic="true" isFinal="true" isStatic="true">.
I suspect there is a faster method, but all I really need to do is try to assign a property value if it exists or can be created.
//The "base is dynamic" test is pseudo-code since it's not valid
if (base.hasOwnProperty(propertyName) || (base is dynamic))
base[propertyName] = value;
else
throw new Error( "Property " + propertyName + " does not exist and cannot be created." );
Perhaps I would be better off just wrapping the assignment in a try/catch block and assuming the class is not dynamic when the assignment fails. If it succeeds, I don't care whether it's dynamic, since the goal is to simply assign the property value if exists or can be added.
try{base[propertyName] = value}catch(err:Error){/*property did not exist and class is not dynamic, or some other error occurred in the property setter*/}
My only issue with the try/catch approach is that I wouldn't know if the assignment failed because the property couldn't be assigned or if some other error occurred in the property setter. Even catching the error and checking its type will not tell me whether the error occurred at this precise point (as opposed to some other setter deep within this setters calling chain), because the getStackTrace method is only available in the debug player. That's why I really need to check whether the class is dynamic up front, so the assignment failure can be reliably predicted and avoided altogether. I will opt for a correct implementation over a faster one.
My suggestion is to go the try/catch route. However, you actually can check to see if it failed because the property couldn't be assigned by either checking the errorID on the generic Error, OR you could catch that specific error before catching others. What you're looking for is 1056 which is a ReferenceError.
Here's an example of the 2nd method I mentioned:
var instanciatedSprite:Sprite = new Sprite();
var nonInstanciatedSprite:Sprite;
var dynamicMovieClip:MovieClip = new MovieClip();
for each(var obj:Object in [dynamicMovieClip, instanciatedSprite, nonInstanciatedSprite]){
try{
obj["abc"] = "abc";
}
catch(e:ReferenceError){
trace("property did not exist and class is not dynamic");
}
catch(e:Error){
trace("not the error you're looking for");
}
}
This will first trace out property did not exist and class is not dynamic when it attempts to assign a property to the instanciatedSprite. Then, when it hits the nonInstanciatedSprite, it will skip that catch and get caught by the generic catch for all other Error types and trace out not the error you're looking for.
Since the only correct way to determine whether the property can be assigned is to check whether the property exists and whether the property can be created, I decided to focus on optimizing the determination of whether the instance is dynamic.
Although the describeType function may be relatively slow, I really only need to call it once per type if I cache the results. I could then store the boolean result in a dictionary by type name or class reference, and then just use the much faster functions getQualifiedClassName and/or getDefinitionByName methods to look up whether the class was dynamic.
public class ClassUtils
{
static var typeDescriptions:Dictionary;
static var isTypeDynamic:Dictionary;
public function isDynamic( instanceOrClass:* ):Boolean
{
var qname:String = getQualifiedClassName(instanceOrClass);
var isDynamic:* = isTypeDynamic[qname];
if (isDynamic === undefined) //only explicitly untyped variables can hold the value undefined with strict equality
{
var desc:XML = getCachedTypeDescription( qname );
isDynamic = Boolean(desc.#isDynamic);
isTypeDynamic[qname] = isDynamic;
}
return isDynamic;
}
public function getCachedTypeDescription( qname:String ):XML
{
var desc:* = typeDescriptions[qname];
if (desc === undefined) //only explicitly untyped variables can hold the value undefined with strict equality
{
desc = describeType( type );
typeDescriptions[qname] = desc;
}
return desc;
}
}
That in turn will allow my original implementation to function quickly and efficiently:
if (base.hasOwnProperty(propertyName) || (ClassUtils.isDynamic(base))
base[propertyName] = value;
else
throw new Error( "Property " + propertyName + " does not exist and cannot be created." );

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.

AS3 Cast Vector to Array

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.

Typed AS3 JSON Encoder and Decoder?

I need to encode and Decode AS3 Objects in a typed manner. http://code.google.com/p/as3corelib/ only supports untyped encoding and decoding.
http://code.google.com/p/ason/ supports some kind of typed objects but is not very robust, e.g. it fails on Date Objects. Any Recommendations ?
To make it clear: It MUST be JSON and it MUST be strong typed and robust.
JSON is built in in AS3. The preferred method to transmit data over the wire is AMF, which does provide you typed objects.
If you have to use JSON, then I guess that you might have to do with some sort of custom protocol to be able encode/decode with types.
You would actually need a reflection utility that read beans in JSON format and then produce your object. It really depends on how deep you want to go.
as3Commons has a reflect package that could help. They also have a JSONTypeProvider, which is not exactly what you need but can put you in the right tract.
You could modify any of the IOC frameworks to produce the context by parsing JSON instead of the regular XML most of them use.
You could modify ASON and add a custom type parser. You would have to send a variable in your JSON object containing the type of the object. And use that in with flash.utils.getDefinitionByName.
Another approach would be to just parse the objects with a regular JSON parser and then if it has a defined type create an instance of that objet, and initialize the properties.
Something like this, to get you started:
var beanInfo:Object = JSON.decode( jsonString );
beanInfo = _parseBean( beanInfo );
private function _parseBean(beanInfo:Object):Object{
if ( beanInfo.hasOwnProperty("_type") ) {
var clazz:Class = getDefinitionByName( beanInfo._type ) as Class;
beanInfo.__clazz = clazz;
var instance:Object = new clazz;
for( var prop:String in beanInfo ) {
if( instance.hasOwnProperty(prop) ) target[prop] = _getPropertyFrom(beanInfo[prop]);
}
}
}
private function _getPropertyFrom(property:String):* {
var xml:XML = describeType( beanInfo.__clazz );
//find the type of the current property.
var type:String = xml...
//if is a simple object then do something like
switch( type ) {
case "number":
return parseFloat(property ) as Number;
break;
case "int":
case "uint":
return parseInt( property );
break;
case "string":
return property as String;
break;
...
default
//As it is it does not suppor complex objects.
//You would use reflection. But then you could save the whole switch...
break;
}
}
Flash has its own serialization system.
var serializer:ByteArray = new ByteArray();
serializer.writeObject(new Sprite());
serializer.position = 0;
var data:String = serializer.readUTFBytes(serializer.bytesAvailable);
trace(data); //Will show you the binary jibberish
You can use registerClassAlias to add support for custom classes.
JSON doens't really define a means to convey type information. It's just strings and ints and arrays and so on. So basically you need some sort of "pickle" for AS3 that's based on JSON. I would suggest you look into Flex/Flash remoting solutions and see how they package objects to be transmitted for RPC; you might be able to modify that solution to use JSON. I'm actually doubtful you'll find a library like this. Does it have to be JSON? I'm pretty sure there are XML based libraries that do this.
JSON is not implemented in the flash virtual machine, and therefore there is no typed object "JSON" as there is "Xml." So basically you can decode JSON just fine, but the type you're going to get is Object. You can them access data using the key in the object as an associative array.
http://blog.alien109.com/2009/02/11/php5-json-as3corelib-a-beautiful-thing/
JSON lib/utils official from adobe:
http://code.google.com/p/as3corelib/source/browse/#svn%2Ftrunk%2Fsrc%2Fcom%2Fadobe%2Fserialization%2Fjson
As good as it gets. :)
There are two operations you need to consider: 1) serializing an object of a particular type into JSON and 2) deserializing a JSON string into an object of a particular type.
The serialization part is easy - just use the built-in JSON.stringify(). Deserializing a JSON string into an object of a particular type in ActionScript is where it gets interesting (and where the answer to your question is). You need to write your own deserialization function for the classe(s) you will need to deserialize. In that function, you need to provide a reviver function to JSON.parse(), which allows you to customize how the JSON gets deserialized.
For example:
public static function deserializeComplexObject(json:String):ComplexObject
{
if (null == json || "null" == json)
{
return null;
}
var complexObject:ComplexObject = new ComplexObject();
var parsedObject:Object = JSON.parse(
json,
function (key:String, value:Object):*
{
switch (key)
{
case “keyForNumber”:
return value;
case “keyForComplexObject2”:
return deserializeComplexObject2(JSON.stringify(value));
case “keyForComplexObject3”:
return deserializeComplexObject3(JSON.stringify(value));
case “keyForString”:
return value;
case “keyForBoolean”:
return value;
default:
return value;
}
}
);
complexObject.keyForNumber = parsedObject.keyForNumber;
complexObject.keyForComplexObject2 = parsedObject.keyForComplexObject2;
// continue setting fields
// …
return complexObject;
}
Each case statement corresponds to a top-level key in the JSON string. You don't actually need separate case statements for every key - you can use the default case to handle all keys that map to values that are one of the simple types (Object, Array, String, Number, Boolean, null) by returning the value as-is.
I have now forked the json part of http://code.google.com/p/as3corelib/ and added typed object support...

What is the equivilant of C#'s generic Dictionary in ActionScript 3?

I want to have a collection of objects, which will be of a class I created called Server. A Server has a string property which is it's IP address, as well as many other pieces of data and objects.
I will have methods for adding and removing servers to this collection, and there will be a need to find a server by it's IP address occasionally. If I were doing this in C# I would use a Dictionary< where the IP string would be the key and the Server object would be the value. I could easily check to see if an item exists in the Dictionary before attempting to add it.
So my requirements are:
1. Ability to add items to the collection (I don't care where they go, front, back, middle)
2. Ability to remove items from anywhere in the collection.
3. Ability to determine if a particular IP address already exists in the collection.
4. Ability to get a reference to a Server object by it's IP.
Edit: Oh yes, I would like it to be strongly typed like the Vector... I guess it's not absolutely necesary, but would be nice.
So it seems like an associative arrays will give me what I need, except I'm not sure about how to do #3 or #4.
public var Servers:Object = new Object( );
public function AddServer(server:Server):void
{
//TODO:need to check if it exists first and throw an error if so
//(it's the caller's responsibility to call DoesServerExist first)
Servers[server.IP] = server;
}
public function RemoveServer(IP:string):void
{
//is it OK to attempt to delete an item if it doesn't already exist?
//do I need to check if it exists before doing delete?
delete Servers[IP];
}
public function DoesServerExist(IP:string):bool
{
//Do I loop through all the elements testing it's IP property?
//Or can I just do something like this?
if(Servers[IP] == null)
{
return false;
}
else
{
return true;
}
}
public function GetServer(IP:string):Server
{
return Servers[IP];//what is returned if this IP doesn't exist?
}
Call me goofy, but why not use the Dictionary class? That gets you everything except strong typing.
If you want strong typing then I'd say you need a custom container, which wraps up a Vector of Servers, and a Dictionary or associative array of IP strings that indexes into the Vector. Then you'd need to expose methods for access, test, insert and remove.
You can just use an array. Example:
var dict:Array = [];
var ip = "164.157.012.122"
dict[ip] = "Server name"
if (dict[ip] == "Server name"){
trace("Yay");
}
//membership
if (dict[ip]){
trace(ip + " is a member of dict");
} else {
trace (ip + " is not a member");
}
//removal:
dict[ip] = null;
AS3 does not really have a built in Dictionary class, unfortunately.