Action Script Convert Function to an Object - actionscript-3

I need to convert a function to an object. For example, when I need to use the variable called fn I want to be able to use it as a function fn() or as an object fn.json(). I have code to do it, but I think it's not correct.
package lib.smartic {
// import
import lib.smartic.smartic;
// constructor $
public var fn = function(s):smartic{
return new smartic(s);
};
Function.prototype.json = function (s) {
// call
};}
How can I apply the prototype to my variable fn, not just to the object class?

Actually, Function is an Object... and as said #The_asMan, you shouldn't use prototypes.
Simple example:
var smartic: Smartic = new Smartic("someValue");
trace(smartic.json());
And definition of your Smartic class, without prototypes:
public class Smartic {
private var _value:String;
public function Smartic(value:String) {
_value = value;
}
public function json():String {
return "Some json here";
}
}

I don't know what you want to do exactily but if you want smartic to be a function you can do something like this:
keep the code givent by Nicolas Siver and add this function:
public function smarticFunc(value:String):Smartic
{
return new Smartic(value);
}
so you can use smarticFunc as function or as Smartic as it returns a Smartic.

Related

use getter setter with static function

I try to use getter/ setter with static function.
Inside a mxml file, I try to get http service like that :
EventColorByDayModel.acListeVac(event.result.ListeVac.VacPeriode);
Indeed, I need to use result to poulate arraycollection inside EventColorByDayModel.
See, below all my class:
package
{
import mx.collections.ArrayCollection;
public class EventColorByDayModel
{
private static var _acListeVac:ArrayCollection;
public static function get acListeVac():ArrayCollection
{
return _acListeVac;
}
public static function set acListeVac(value:ArrayCollection):void
{
_acListeVac = value;
}
public static function getEventColorByDate(date:Date):uint
{
var result:uint = 0xE3EBF6;
// Store renderer
for each ( var item:Object in _acListeVac )
{
if (( item.dateMySQLDeb.time <=date.time )&&( date.time<=item.dateMySQLFin.time ))
result = uint(item.sColor);
}
return result;
}
public function EventColorByDayModel()
{
}
}
}
But, in that case, an error appear with message, "impossible to access to acListeVac with a ref static Class".
I try to translate message error french to english. I hope, it's comprehensive.
Thanks for helping.
Because it is a setter (specified by the set keyword), you just set the value like any other variable. So try this instead of the first line of code you have up there:
EventColorByDayModel.acListeVac = event.result.ListeVac.VacPeriode;

Overriding function from another class

I am defining this function in one of my classes:
public function onUse():void {};
Then in another of my classes (let's call it "class2"), I create a object of this class, and then want to override this function with another one. After some Google-Fu, I have found this, and used it...
button.onUse {
variable = value;
}
...but it executes instantly, and not when onUse() is called - which seems to be an empty function, always.
I didn't find anything more than that - I tried a few things myself, like specifying a function inside class2 and using button.onUse = function();, but it always throws errors.
Can anyone tell me whether what I am trying to do is actually possible, and if it is, how can I do it?
You can only override functions when you are extending the class:
public class A {
public function foo():void {
doStuff();
}
}
public class B extends A {
override public function foo():void {
doOtherStuff();
}
}
var n:A = new A();
n.foo(); // => calls doStuff();
var o:B = new B();
o.foo(); // => calls doOtherStuff();
Hence, assigning a different function to a class method of an instance is not possible at runtime.
You can, however, let your original class contain a field of type Function, and then simply assign a different closure to it.
public class A {
public var foo:Function;
}
var n:A = new A();
n.foo = function ():void {
doStuff();
};
n.foo(); // => calls doStuff();
var o:A = new A();
o.foo = function ():void {
doOtherStuff();
}
o.foo(); // => calls doOtherStuff();
check the syntax of
button.onUse {
variable = value;
}
a function would be defined as
public function onUse():void {};
and overwritten with
override public function onUse():void {
}
in a different class
the way you're trying to do it, does not constitute overriding a function.
What I've done in similar circumstances is create a onClickFunction function in the class
public var onClickFunction:Function = null;
and then in the CLICK event listener function add
if(onClickFunction != null){
onClickFunction();
}
then you can assign your on-click functionality by doing something like this
button.onClickFunction = function():void{
variable = value;
// dostuff
}
this is not the best way of doing it, but probably the easiest way of implementing the functionality. And ideally you'd use inheritance the way the spacepirate suggested.

Function call(thisArg:*, ... args) first parameter usage in actionscript

what does call(thisArg:*, ... args) first parameter mean?
Assuming f() is defined in a unnamed package as global function, following is the code snippet:
package {
public function f(message:String):void {
trace(message);
trace(this.watchedValue);
}
}
test code as following:
public function test():void {
var obj:Object = {watchedValue:100};
f("invoking f");
f.call(obj, "invoking f by call()");//actual result is undefined, but shouldn't be 100?
}
This param only used in closures and anonymous functions, like
var testFunc:Function = function():void{trace(this.watchedValue)}
EDIT:
in you case it will be
package {
public var f:Function = function(message:String):void {
trace(message);
trace(this.watchedValue);
}
}
EDIT2
first parameter of call will be this in called function. This is the way to call fauction like a method of object.
But when function is method or top level function first parameter of call() will be ignored. To use first param your function must be variable with anonymous function.
As far as I know Function.call() is the same as function(), except the fact you change the scope of this. Normally this referrers to the current class, but it could be another class. \
Your test function looks wrong, it should be obj instead of o
public function test():void {
var obj:Object = {watchedValue:100};
f("invoking f");
f.call(obj, "invoking f by call()");
}

How can I pass all parameters (one by one) in an object to a constructor in AS3?

This is a hard question to do, but I'll try to explain.
I have the Class and the parameters of its contructor as an object. What I need to do is a function that returns an instance of this class, passing this parameters to the constructor.
This is the code:
Some random and unmodifiable class:
public Foo {
public function Foo(a:int, b:String) {
// constructor
}
}
And some function (in some another class):
function bar(params:Object):* {
var baz:Foo = new Foo(params.a, params.b);
return baz;
}
What I need to do is make this function generic, without pass params as parameter to Foo constructor because I can't modify it. Something like:
function bar2(clazz:Class, params:Object):* {
var baz:* = new clazz(/*some magic way to transform params in comma separated parameters*/);
return baz;
}
Anyone can help me?
Thanks a lot.
This is called parameterized factory. First I thought about Function.apply, but it doesn't apply to constructors (he-he). So, people are making factories like this:
function create(what:Class, args:Array):* {
switch (args.length) {
case 0: return new what();
case 1: return new what(args[0]);
case 2: return new what(args[0], args[1]);
...
//PROFIT!
}
throw new Error("Need moar cases!");
}
what about using ByteArrayto copy the object ?
function clone(source:Object):* {
var copier:ByteArray = new ByteArray();
copier.writeObject(source);
copier.position = 0;
return(copier.readObject());
}
newObjectCopy = clone(originalObject);
source
If you have the option of not using a constructor, but adding an initialise() function to each class which can be constructed instead, you could use Function.apply - something like in the example below.
public class ThingCreator
{
public static function createTheThing(c:Class, params:Array):Object
{
var the_thing:Object = new c();
the_thing.initialise.apply(the_thing, params);
return the_thing;
}
}
As alxx pointed out above, Function.apply and AS3 reflection in this case does not seem to work with AS3's constructors.

Does AS3 provide any way to stop a returned object being modified?

If an AS3 method returns a reference to a complex type, is there any way to make that 'readonly', like how you can have const member functions in C++? An architecture I want to use calls for a class building itself from a passed template object... and really the template object should not be modifiable. I'm currently forced to add call-back enumerators and/or lots of extra accessor methods.
Flex has an ObjectUtil.clone() method that will make a deep copy. The copy will still by modifiable, but since it's a copy, the changes won't propagate back to the original.
The method is no complicated so if you're not using Flex, just add this to a util class:
public static function copy(value:Object):Object
{
var buffer:ByteArray = new ByteArray();
buffer.writeObject(value);
buffer.position = 0;
var result:Object = buffer.readObject();
return result;
}
There is no way to do that in AS3, there is Sam's way of doing it, but it still requires copying that object before you return it, depending on the complexity of that object, it can impact the performance.
Immutable interfaces are a near-equivillant to const-correctness. Here's an example:
interface CPoint {
function get x():Number;
function get y():Number;
}
class Point implements CPoint {
private var _x:Number;
private var _y:Number;
public function get x():Number { return _x; }
public function get y():Number { return _y; }
public function set x(val:Number) { _x = val; }
public function set y(val:Number) { _y = val; }
public function normalize():void {
var length:Number = Math.sqrt(_x*_x + _y*_y);
_x /= length;
_y /= length;
}
public function Point(x:Number, y:Number) {
_x = x; _y = y;
}
}
If you return a Point as a CPoint reference, then its fields cannot be altered. You can do an explicit cast to a Point from a CPoint to force access, but you can do the same thing with const casting in C++.
Unfortunately, AS3 doesn't support covariance like it should, so things get unnecessarily difficult for const sub-objects. For example, if you had a Line class that was made up of two points, you might want to say line.start.x = 47; if you have full access to the line, but allow reading of line.start.x through an immutable interface. You could do this if there was covariance, but instead you'll need to add separate get properties for mutable and immutable properties. So, you'd end up instead with line.cstart.x for reads from a CLine. Something like this:
interface CLine {
function get cstart():CPoint;
function get cend():CPoint;
}
class Line implements CLine {
private var _end:Point;
private var _start:Point;
public function get cend():CPoint { return _end; }
public function get cstart():CPoint { return _start; }
public function get end():Point { return _end; }
public function get start():Point { return _start; }
public function Line(x1:Number, y1:Number, x2:Number, y2:Number) {
_start = new Point(x1, y1);
_end = new Point(x2, y2);
}
}
I would create a flash.utils.proxy object. You could create a proxy object that has read only implementation of a child that is passed in.
Here is the documentation for creating a proxy object. http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/utils/Proxy.html
Note: Proxy is pretty damn slow, since you'll be bypassing native object checking, and replacing it with a function call -- which when using a lot will be slow. I would do some simple performance testing first.
note: This is pseudo-code.
use namespace flash_proxy;
dynamic class ReadOnly extends flash.utils.Proxy {
private var target:Object;
public function ReadOnly(target:Object) {
this.target = target;
}
flash_proxy function getProperty(name:*):*
return target[name];
}
flash_proxy function setProperty(name:*, value:*):void
// throw an error or do nothing
}
}
You could then do:
var readOnly:ReadOnly = new ReadOnly(stage.loaderInfo.parameters);
readOnly.someparameter = 'newvalue';
trace(readOnly.someparameter); // should be old value