How to test if an object is a vector? - actionscript-3

I want to test if an object is a vector, any vector, not only a vector of a single type.
I ran a test:
var v:Vector.<int> = new Vector.<int>();
v.push(3);
v.push(1);
v.push(2);
trace(v is Array); // false
trace(v is Vector); // false
trace(v is Vector.<int>); // true
trace(v is Vector.<*>); // false
It seems that the only thing that returns true is the one which specifies the vector type, but I want to test it for ANY type.
I will need a very efficient method to compare, because getQualifiedClassName is too slow.
My current approach is:
private static function isVector(obj:Object):Boolean {
return (getQualifiedClassName(obj).indexOf('__AS3__.vec::Vector') == 0);
}
But it is 2x slower than the is operator.
I need speed because it's for a object serialization class, and it needs to be very fast.

The problem is that Vector.<*> is a different class than that used for <Number>, <int>, or <uint>. The numeric primitives have special classes for better efficiency. String and Boolean are also primitives, but unlike the numeric primitives they are detected by <*>. As a result, you need only test for the generic Vector and the 3 numeric types.
This solution is over 2 times as fast as getQualifiedClassName in the worst case where the object is either not a Vector, or is a Vector.<uint>, and 5 times faster if the object is a non-primitive base type Vector, like Vector.<Object>:
return (obj is Vector.<*>
|| obj is Vector.<Number>
|| obj is Vector.<int>
|| obj is Vector.<uint>);
Here's a simplistic test:
var moo:Vector.<uint> = new Vector.<uint>();
var timer:Timer = new Timer();
var b:Boolean;
timer.startTimer();
for (var i:int = 0; i < 1000000; i++)
{
b = (moo is Vector.<*>
|| moo is Vector.<Number>
|| moo is Vector.<int>
|| moo is Vector.<uint>);
}
logger.info(" is timer: " + timer.endTimer());
timer.startTimer();
for (i = 0; i < 1000000; i++)
{
b = (flash.utils.getQualifiedClassName(moo).indexOf('__AS3__.vec::Vector') == 0);
}
logger.info("gqcn timer: " + timer.endTimer());
[LOG] com.tcg.test: is timer: 320
[LOG] com.tcg.test: gqcn timer: 756
Change moo to Vector.<Object>:
[LOG] com.tcg.test: is timer: 158
[LOG] com.tcg.test: gqcn timer: 743

Other methods are way too inefficient, so I'm still using my approach:
private static function isVector(obj:Object):Boolean {
return (getQualifiedClassName(obj).indexOf('__AS3__.vec::Vector') == 0);
}

trace(new Array().fixed);//undefined
trace(new Object().fixed);//undefined
trace(new Vector.<Sprite>().fixed);//false
trace(new Vector.<*>().fixed);// false

If you need serialization for any kind of object, you have to iterate over all possible types anyway, so you could use a sequential approach to find your vector type:
v is ... (simple data types)
v is ... (object types that are not collections)
v is Array
v is XMLList
v is ... (all other collection types you can think of)
if none of the above is true, it must be a vector
serialize objects in the vector. If you have more than one type, it's Vector.<*>, otherwise set the vector type according to the object type of the content items.

Use
(obj as Vector.<*>) is Vector.<*>

/// Return Class of any Target
static public function getClass( Target:* ):Class
{
return getDefinitionByName ( getQualifiedClassName( Target ) ) as Class ;
}
/// Check if object is type of Vector.< * >
static public function isVector( any:* ):Boolean
{
return String( getClass( any ) ).indexOf( "[class Vector.<" ) > -1;
}
/// Get Vector < Class >
static public function getVectorType( vector:* ):Class
{
var c:String = String( getClass( vector ) );
var s:int = c.indexOf( '<' ) + 1;
var e:int = c.indexOf( '>' );
return getDefinitionByName( c.substring( s, e ) ) as Class;
}

private function getIsVector(obj:Object):Boolean
{
return String(obj.constructor).indexOf('[class Vector.<*>]') == 0;
}

Related

Defining the interface for a function using function properties

As you may know, functions in JavaScript can have properties as any object. For example (taken from the excellent JavaScript: The Definitive Guide, 6th ed, p. 178) computes a factorial using the function as memoization array:
function factorial(n: number): number {
if (isFinite(n) && n > 0 && n == Math.round(n)) {
if (!(n in factorial))
factorial[n] = n * factorial(n - 1);
return factorial[n];
}
else
return NaN;
}
factorial[1] = 1;
I tried defining the following interface:
interface Factorial {
(n: number) : number;
[ index: number ]: number;
}
But the compiler is telling me that Type '(n: number) => number' is not assignable to type 'Factorial'. Index signature is missing in type '(n: number) => number'.
I can't do the obvious thing and just define private index: number; inside the function, I'm stumped.
What you have is an example of hybrid types. You have to use type assertion to make sure the function complies with the interface:
let factorial = function (n: number): number {
if (isFinite(n) && n > 0 && n == Math.round(n)) {
if (!(n in factorial))
factorial[n] = n * factorial(n - 1);
return factorial[n];
}
else
return NaN;
} as Factorial;
factorial[1] = 1;

json C# 7 Tuple Support

I want to get my C#7 tuple property names in my JSON (Newtonsoft.Json) output.
My problem is:
When I want to convert my tuple to JSON format that not support my parameters names.
For example this is my "Test2" method and you can see the JSON output:
public void Test2()
{
var data = GetMe2("ok");
var jsondata = JsonConvert.SerializeObject(data);//JSON output is {"Item1":5,"Item2":"ok ali"}
}
public (int MyValue, string Name) GetMe2(string name)
{
return (5, name + " ali");
}
The JSON output is "{"Item1":5,"Item2":"ok ali"}" but i want "{"MyValue":5,"Name":"ok ali"}";
This is not impossible because I can get property names in runtime:
foreach (var item in this.GetType().GetMethods())
{
dynamic attribs = item.ReturnTypeCustomAttributes;
if (attribs.CustomAttributes != null && attribs.CustomAttributes.Count > 0)
{
foreach (var at in attribs.CustomAttributes)
{
if (at is System.Reflection.CustomAttributeData)
{
var ng = ((System.Reflection.CustomAttributeData)at).ConstructorArguments;
foreach (var ca in ng)
{
foreach (var val in (IEnumerable<System.Reflection.CustomAttributeTypedArgument>)ca.Value)
{
var PropertyNameName = val.Value;
Console.WriteLine(PropertyNameName);//here is property names of C#7 tuple
}
}
}
}
dynamic data = attribs.CustomAttributes[0];
var data2 = data.ConstructorArguments;
}
}
For the specific case here, it is impossible. That's because SerializeObject has no way of finding out where the tuple came from, all it sees is ValueTuple<int, string>.
The situation would be different if you were serializing an object with tuple properties, in which case SerializeObject could use reflection to find the TupleElementNames attributes (even though it currently doesn't).
The short answer it that tuples don't have properties.
A tuple is a bag of values used, mainly, to return multiple values from a method.
They were never intended to model entities.
The only way to solve your problem, if you don't want to create a type for that, is:
public void Test2()
{
var data = GetMe2("ok");
var jsondata = JsonConvert.SerializeObject(new { data.MyValue, data.Name });//JSON output is {"Item1":5,"Item2":"ok ali"}
}

How to view and bind an array with swing builder

Currently, this shows 2 variables on the screen. Whenever that variable changes, it is also shown on the GUI.
I would like to bind array indexes in a similar way. For example: x[1],
and whenever x[1] changes, so does the value shows on GUI
EDIT: array x doesn't update, I also don't want the whole array but each index on a new line.
import groovy.swing.SwingBuilder
import groovy.beans.Bindable
#Bindable
class controller{
boolean stop = false;
String status = "RUNNING";
String name = "";
String[] x= new String[5];
}
def ctrl = new controller();
def UI = new SwingBuilder().edt {
frame(title: 'Menu', size: [220, 150], locationRelativeTo: null, show: true, alwaysOnTop: true){
gridLayout(cols:1, rows: 5)
label(text: bind(source: ctrl, sourceProperty: 'status', converter: { v -> v? "Status: $v": ''}))
label(text: bind(source: ctrl, sourceProperty: 'name', converter: { v -> v? "$v": ''}))
label(text: bind(source: ctrl, sourceProperty: 'x', converter: { v -> v? "$v": ''}))
}
}
for(i = 0; i < 5 ; i++){
sleep(500);
ctrl.name+= "Hi there ";
ctrl.x[i] = "T"+i;
}
ctrl.status = "DONE";
sleep(1000);
UI.dispose();
You can't observe changes on an array using #Bindable in this way. The AST transformation is a convenience for registering methods that rely on PropertyChange and PropertyChangeListener.
Changes made to name and status properties work because you're replacing their value, thus a PropertyChangeEvent is triggered for every change. However for the x property you're not changing the array reference, but the elements within the array.
You have two options to make this work:
either observe changes on the index itself (add an Integer property to the controller class).
use an ObservableList instead of an array.
Personally I prefer option #1. You will have to use a converter such as
label(text: bind(source: ctrl, sourceProperty: 'index', converter: { v -> v != -1? ctrl.x[v]: ''}))
Notice the use of -1 to check for a selected index as a value of 0 would make the previous check (v?) fail due to Groovy Truth.
The controller class can be updated as follows
#Bindable
class controller{
boolean stop = false;
String status = "RUNNING";
String name = "";
String[] x= new String[5];
int index = -1;
}

Can you override functions in AS3?

I am new to ActionScripting but I have done some Java. I was told they are kinda similar. I am coding my swf file with some AS3 integrated.
function init():void{
// do something
}
function init(var string:String):String{
// do something else
}
is this not allowed in AS? If not, is there another way of handling it besides?
Thanks in advance.
Yes, you can override functions. But the example you gave is not overriding - it's overloading. For overriding a function, you basically just create a function with the same signature and everything in a subclass and add the word "override" right before it.
You can't directly overload a function though. If you want a variable number of parameters, you have to use optional parameters instead. Like this:
function init(str:String = null):String
{
if (str == null)
{
// do one thing
return null;
}
else
{
// do another thing
return "someString";
}
}
And that's about the best you're going to be able to do in AS3. The inability to overload functions, at least strictly speaking, is a fairly common complaint and obvious shortcoming of the language.
Do you mean method overloading? Actionscript, sadly, does not support this.
To get around it, you can use default parameters, or just make your parameters a bit less constraining. This answer has some details on that.
You could try this:
function init(var string:String = "Default value"):String{
// do something
}
Actionscript does not support method overloading. However, based on the answer to this question you have other options.
If you just want to be able to accept any type, you can use * to
allow any type:
function someFunction( xx:*, yy:*, flag:Boolean = true )
{
if (xx is Number) {
...do stuff...
} else if (xx is String) {
...do stuff...
} else {
...do stuff...
}
}
If you have a large number of various parameters where order is
unimportant, use an options object:
function someFunction( options:Object )
{
if (options.foo) doFoo();
if (options.bar) doBar();
baz = options.baz || 15;
...etc...
}
If you have a variable number of parameters, you can use the ...
(rest) parameter:
function someFunction( ... args)
{
switch (args.length)
{
case 2:
arr = args[0];
someBool = args[1];
xx = arr[0];
yy = arr[1];
break;
case 3:
xx = args[0];
yy = args[1];
someBool = args[2];
break;
default:
throw ...whatever...
}
...do more stuff...
}
For cases where you need to call a common function to a number of
classes, you should specify the interface common to each class:
function foo( bar:IBazable, flag:Boolean )
{
...do stuff...
baz = bar.baz()
...do more stuff...
}

How can I introspect the signature of a Flex function?

Given a function like
function printAndAdd( s: String, a: int, b: int ) {
// ...
}
Is there any way to enumerate the arguments of the function (their names as well as their types) at runtime? Something like
for ( var arg: ArgumentDescriptor in printAndAdd ) {
// arg.type yields the class object of the argument, i.e. 'String' or 'int'.
// arg.name yields the name of the argument, i.e. 's' or 'a'
}
I have a list of event handlers which have different signatures, and I get the name of the event handler to call as well as an Array of objects. I could just apply() the array to the function, but I'd like to do some error checking first to give better error messages.
You can use describeType() to find the information you seek. However for this to work the function must be public. Private methods will not be introspected by describeType().
Assuming printAndAdd is a method of MyClass, you can do this:
var metadata:XML = describeType(MyClass);
//find all the 'parameter' nodes of any method called 'printAndAdd'
var params:XMLList = metadata..method.(#name == "printAndAdd").parameter;
for each (var param:XML in params) {
var index:int = param.#index;
var type:String = param.#type;
var optional:Boolean = param.#optional == "true";
}
One thing you will not be able to find, is the name of the paramater, but I suppose its index may suffice for your goal.
If you need more powerful reflection than this, take a look at the as3commons reflect library.