How is this function return value being ignored in Actionscript? - actionscript-3

I'm trying to port the Box2DFlashAS3 physics engine to another language (Xojo). I am not particularly fluent in Actionscript (but am more so than I am with C++ which Box2D was originally written in).
As I understand it, parameters passed to functions in Actionscript as done so by reference. Consider these two classes (greatly cut down for simplicity, it's the two GetInverse() functions I'm interested in):
public class b2Mat22 {
public function GetInverse(out:b2Mat22) : b2Mat22 {
var a:Number = col1.x;
var b:Number = col2.x;
var c:Number = col1.y;
var d:Number = col2.y;
var det:Number = a * d - b * c;
if (det != 0.0)
{
det = 1.0 / det;
}
out.col1.x = det * d; out.col2.x = -det * b;
out.col1.y = -det * c; out.col2.y = det * a;
return out;
}
public var col1:b2Vec2 = new b2Vec2();
public var col2:b2Vec2 = new b2Vec2();
}
and
public class b2Transform {
public function GetInverse(out:b2Transform = null) : b2Transform {
if (!out)
out = new b2Transform();
R.GetInverse(out.R);
out.position.SetV(b2Math.MulMV(out.R, position));
out.position.NegativeSelf();
return out;
}
public var position:b2Vec2 = new b2Vec2();
public var R:b2Mat22 = new b2Mat22();
}
I don't understand R.GetInverse(out.R); in the b2Transform class. Doesn't the GetInverse() function of the b2Mat22 class return a value? If so, why is it not being used?

That a function returns a value does not mean that this value needs to be used.
Here is an example:
Array - reverse()
Returns: Array — The new array.
Reverses the array in place.
var letters:Array = new Array("a", "b", "c");
trace(letters); // a,b,c
letters.reverse();
trace(letters); // c,b,a
You can see it modifies the array but it STILL returns the new array. This can be used for some techniques like method chaining:
myArray.reverse().concat(...) //you couldn't do this if it didn't return the new array, in that case you would have to do this:
// --->
myArray.reverse();
myArray.concat(...);
Also note that in AS (just like in JS, Java, etc.) the parameter is passed by reference if it is an object but the primitive values are not passed by reference.
Now to say the complete truth I have no idea what those methods from Box2D do, but I believe this might be the case.

Related

How can I translate keyword prototype in AS3 to Haxe?

I have the below AS3 code, and I want to translate it to Haxe. But I don't know how to deal with the keyword prototype. Who can help me? Thanks.
var style = new CSSStyleDeclaration();
style.defaultFactory = function():void
{
this.disabledOverlayAlpha = 0;
this.borderStyle = "controlBar";
this.paddingTop = 10;
this.verticalAlign = "middle";
this.paddingLeft = 10;
this.paddingBottom = 10;
this.paddingRight = 10;
};
if(chain == null) chain = {};
style.defaultFactory.prototype = chain;
chain = new style.defaultFactory();
style.defaultFactory = function():void
{
this.fontWeight = "bold";
};
style.defaultFactory.prototype = chain;
chain = new style.defaultFactory();
style.defaultFactory = function():void
{
this.backgroundSize = "100%";
this.paddingTop = 24;
this.backgroundColor = 8821927;
this.backgroundImage = ApplicationBackground;
this.horizontalAlign = "center";
this.backgroundGradientAlphas = [1,1];
this.paddingLeft = 24;
this.paddingBottom = 24;
this.paddingRight = 24;
};
style.defaultFactory.prototype = chain;
chain = new style.defaultFactory();
Ok, I poked this a bit, and now I kind of figured out, what that piece of code does. This knowledge won't help you to port your code to HAXE, but it will help you understand what it is about and to compose a decent HAXE-style alternative.
First, the part about instantiating, functions and working with prototypes. As it turned out, if you invoke the new operator on an unbound function (does not work on class methods):
The new empty class-less generic Object is created.
Its reference is passed to the said function as this.
The function can add and modify the object's fields and methods.
Ultimately, the reference to that Object is returned.
Then, it works (as I mentioned in my comments above) very much the way classes worked back then in AS1 and Flash 6.
If that function has a prototype and it is too a generic Object, then it is added to the newly created one as a... how to put it... a bottom layer Object which adds its fields to the top layer Object.
I understand that it sounds difficult, so there's an explanatory example that somehow sheds some light on it all:
public class Proton extends Sprite
{
public function Proton()
{
super();
var P:Function;
// Empty.
P = new Function;
create("First:", P);
// Empty with prototype.
P.prototype = {c:3, d:4};
create("Second:", P);
// Non-empty.
P = function():void
{
this.a = 1;
this.b = 2;
};
create("Third:", P);
// Non-empty with prototype.
P.prototype = {a:5, f:6};
create("Fourth:", P);
}
// Instantiates the F and outputs the result.
private function create(prefix:String, F:Function):void
{
var A:Object = new F;
trace(prefix + "\nJSON:" + JSON.stringify(A) + "\nREAL:" + explore(A) + "\n");
}
// Same as JSON.stringify, but also looks into the prototype.
private function explore(O:Object):String
{
var result:Array = new Array;
for (var akey:String in O)
{
result.push('"' + akey + '":' + O[akey]);
}
return "{" + result.join(",") + "}";
}
}
So, the output is:
First:
JSON:{}
REAL:{}
Second:
JSON:{}
REAL:{"d":4,"c":3}
Third:
JSON:{"b":2,"a":1}
REAL:{"b":2,"a":1}
Fourth:
JSON:{"b":2,"a":1}
REAL:{"b":2,"a":1,"f":6,"a":1}
As you can see, JSON.stringify exports only the top layer object, while direct for iteration goes through all the layers, top to bottom, and even processes the duplicate keys (but the top layer value shadows what's below).
Second, how it all is related to your code. These factory and defaultFactory functions are used in some CSS-related class to form an Object representation of the style: https://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/styles/CSSStyleDeclaration.html
So, you can use that prototype hack to form a generic Object with a chain of layers upon layers of CSS declarations... probably. You saw that JSON doesn't perceive anything but the top layer, I have no idea if CSS classes act differently or not.
I think, working with CSS should be less hack-y and more straightforward.
Good luck figuring it out.

Use my existing function to calculate new values without replacing existing ones

I've got this code that calculates tides. The function is huge and use the date and the port to calculate it.
There are 4 results :
haute1
haute2
basse1
basse2
Now, I'd like to calculate 4 new values (for date +1) without trigerring the all function with the new date, as it will change the value of haute1, haute2, basse1, basse2..
I only want to create new values "haute1_tomorrow" with the existing function.
Any idea if it's possible ?
What I was doing was calling the existing function like this :
maree("city, tomorrow_date);
with tomorrow_date as the date of tomorrow. But it would only trigger the function and set new values for haute1, haute2, basse1, basse2.
What I'd like is to keep these values, and create 4 new values haute1_tomorrow, haute2_tomorrow, basse1_tomorrow and basse2_tomorrow.
My function (I won't paste the entire function as it would be too long for you to read it) :
function get haute1():String { return $pmm; };
function get haute2():String { return $pms; }
function get basse1():String { return $bmm; };
function get basse2():String { return $bms; };
// convenient way to retrieve public data
function get results():Object
{
if (!$pmm) return {};
return {
haute1:$pmm,
haute2:$pms,
basse1:$bmm,
basse2:$bms,
};
}
function maree($inputport:String = "", $inputdate:String = "", onDataCompleteFunc:Function = null):void
{
if (onDataCompleteFunc != null) _onDataCompleteFunc = onDataCompleteFunc;
$port_maree = trim($inputport).toUpperCase();
/*if ($inputdate != '') $infodate = getdate(date2timestamp($inputdate + " 00:00:00","d/m/Y h:i:s"));
else $infodate = getdate(date2timestamp(date("dmY") + " 00:00:00","d/m/Y h:i:s"));
$jour_maree = $infodate["mday"];
$mois_maree = $infodate["mon"];
$annee_maree = $infodate["year"];*/
var $infodate:Array = $inputdate.split("/");
$jour_maree = Number($infodate[0]); // 25; // Day
$mois_maree = Number($infodate[1]); // 12; // Month
$annee_maree = Number($infodate[2]); // 2015; // Year
loadXmlData();
}
...
..
.
You need OOP: Object-Oriented Programming.
With no regard to your actual problem, the basic approach to problems like that is making a component/class that is self-sufficient to solve one instance of your problem. For example:
package
{
public class Trigonometry
{
public var degrees:Number;
public var radians:Number;
public var sine:Number;
public var cosine:Number;
public var tangent:Number;
public function Trigonometry(value:Number)
{
// Normalize degrees to -180..+180.
value %= 360;
if (value >= 180) value -= 360;
if (value < -180) value += 360;
degrees = value;
radians = value * Math.PI / 2;
sine = Math.sin(radians);
cosine = Math.cos(radians);
tangent = Math.tan(radians);
}
}
}
Then you work with instances which are independent and isolated and don't mess with each other's fields:
var A30:Trigonometry = new Trigonometry(30);
var A45:Trigonometry = new Trigonometry(45);
var A60:Trigonometry = new Trigonometry(60);
var A90:Trigonometry = new Trigonometry(90);
trace("Sine of 30 degrees is:", A30.sine);
trace("Cosine of 60 degrees is:", A60.cosine);
trace("Tangent of 45 degrees is:", A45.tangent);
UPD: Then with your task, you need something like that:
package
{
public class Mar
{
// Here you need to declare all the variables you are going to use.
// Like (I don't know what type you need):
public var $pmm:String;
public var $pms:String;
private var callback:Function;
// Then put all the methods you need:
public function maree($inputport:String = "", $inputdate:String = "", handler:Function = null):void
{
callback = handler;
// Your processing here.
}
}
}
Then you use it exactly the same:
var M1:Mar = new Mar;
var M2:Mar = new Mar;
M1.maree(/* first call arguments here */);
M2.maree(/* second call arguments here */);
So the instances will operate with no regard to each other existence, and you access to their respective fields like:
trace(M1.$pmm);
trace(M1.$pms);

Existing class to get property chain in ActionScript3?

Is there an existing class in Flash or Flex that gets the value from an object from it's property chain?
For example, something like this:
private function labelFunction(item:Object, column:GridColumn):String {
// where dataField equals "fields.status.name"
var value:String = PropertyChain.getValue(field, column.dataField);
return value;
}
~~~ Update ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I found this private method in the Binding class as well that could probably be used in a custom class:
/**
* #private
*/
private static function getFirstWord(destStr:String):String
{
// indexPeriod and indexBracket will be equal only if they
// both are -1.
var indexPeriod:int = destStr.indexOf(".");
var indexBracket:int = destStr.indexOf("[");
if (indexPeriod == indexBracket)
return destStr;
// Get the characters leading up to the first period or
// bracket.
var minIndex:int = Math.min(indexPeriod, indexBracket);
if (minIndex == -1)
minIndex = Math.max(indexPeriod, indexBracket);
return destStr.substr(0, minIndex);
}
I don't think there's an existing function. But it's very easy to build one, and it need not be restricted to generic Object sources, as any member of any object can be retrieved by name using square bracket notation. This simple version doesn't do any validation:
public static function getByName(root:*, member:String):* {
var memlist:Array = member.split('.');
var temp:* = root;
for(var i:uint = 0; i < memlist.length; i++)
temp = temp[memlist[i]];
return temp;
}
// And you can use this even on strongly-typed values, such as a MovieClip:
trace("stageWidth =", SomeUtil.getByName(mc, "stage.stageWidth"));

as3 operator= /(object assign )

I know that AS3 does not have pointer or reference. Every object is pass by reference already. (I supposed?)
What should I do if I want to do with pointer?
e.g. all object point to one target, I only need to change target's value, then all other object will access different value.
You can effectively get the same behavior by using a helper object to simulate a pointer -- in other words using it to carry the target reference. For instance:
public class PseudoPointer
{
private var obj:Object;
private var prop:String;
public function PseudoPointer(obj:Object, prop:String)
{
// Point to property with name 'prop' on object 'obj'.
this.obj = obj;
this.prop = prop;
}
public function get value():* {
return obj[prop];
}
public function set value(value:*):void {
obj[prop] = value;
}
}
Then you could do this -- assume there's a magicNumber property on an object named target:
var numberPtr = new PseudoPointer(target, "magicNumber");
myDynamicObjectA.numberPtr = numberPtr;
myDynamicObjectB.numberPtr = numberPtr;
myDynamicObjectC.numberPtr = numberPtr;
Now any object that has a reference to the pseudo-pointer can read and write the target property:
numberPtr.value = 42;
You could create a function and in which you give it the value and then subsequently assign it to all of those other variables.
Something like below:
var objectA:Number;
var objectB:Number;
...
function myFunction(newValue:Number):void
{
objectA = newValue;
objectB = newValue;
...
}
You could try setting a variable reference to a function. Then if you update that reference, it would return a different function.
var myFunc:Function;
function funcOne():int {
return 1;
}
function funcTwo():int {
return 2;
}
function getFunc():Function {
return myFunc;
}
myFunc = funcOne;
var myObjOne:Object = new Object();
myObjOne.objFunc = getFunc;
var myObjTwo:Object = new Object();
myObjTwo.objFunc = getFunc;
trace(myObjOne.objFunc.call().call()); // 1
trace(myObjTwo.objFunc.call().call()); // 1
myFunc = funcTwo;
trace(myObjOne.objFunc.call().call()); // 2
trace(myObjTwo.objFunc.call().call()); // 2
This allows any object to point at a single function and have what that returns be updateable for all of them simultaneously. It's not the prettiest code and it's not as type-safe as if ActionScript had delegates to enforce the signatures of what's set for myFunc, but it is still a pretty flexible model if you get creative with it.
Have those pointers point to something that contains the object or has the object as a property on it.
So
var myArr:Array = [new YourObject()];
var client1:ArrayClient = new ArrayClient();
client1.array = myArr;
var client2:ArrayClient = new ArrayClient();
client2.array = myArr;
myArr[0] = new YourObject();
//client1.array[0]==client2.array[0]==the new object
However, this seems to be a great way to get yourself into a lot of trouble really quickly. What's the use case?

Ruby-like Question: Make this function shorter (ActionScript 3)

I just wrote this incredibly verbose code to turn numbers like 2 into 02. Can you make this function shorter, please (maintaning the functionality)?
public static function format(n:int, minimumLength:int):String {
var retVal:String = n.toString();
var stillNeed:int = minimumLength - retVal.length;
for (var i:int = 0; i < stillNeed; i++) {
retVal = "0" + retVal;
}
return retVal;
}
Please use types for variables. Extra points (good-vibe points, not SO points) if there's already a built-in function that I don't know about.
If anybody wants to post some extremely short equivalent in some other language, that would be fun too.
This wouldn't be the fastest implementation (it does some unnecessary copying and has a loop), but it is nice and readable:
public static function pad(num:int, minLength:uint):String {
var str:String = num.toString();
while (str.length < minLength) str = "0" + str;
return str;
}
I don't think there is a built-in way, but this might be cleaner (if not necessarily better performing):
//20 zeroes, could be more if needed
public static var Zeroes:String = "00000000000000000000"
public static function format(n:Number, minimumLength:int):String {
var retVal:String = (n.toFixed(0)); // cut off the decimals
var stillNeed:int = minimumLength - retVal.length;
retVal = Zeroes.substring(0, stillNeed) + retVal;
return retVal;
}
The "zeroes" var eliminates the need for looping, just prepend however many zeroes you need from a prebuilt string.
Christophe Herreman almost got it right, but his method adds more zeroes and not the differential amount. I fixed it a bit:
public static function format(n:int, minimumLength:int):String {
var v:String = n.toString();
var stillNeed:int = minimumLength - v.length;
return (stillNeed > 0) ? v : String(Math.pow(10, stillNeed) + v).substr(1);
}
My earlier try:
public static function format(n:int, minimumLength:int):String {
var stillNeed:int = minimumLength - n.toString().length;
return (n.split("").reverse().join("") as int) // 32 -> 23
*Math.pow(10, stillNeed > 0 ? stillNeed : 0).toString() // 23000
.split("").reverse().join(""); // 00032
}
public static function formatAny(n:Number, minimumLength:int):String {
return format((int)n) + n.toString().split('.')[ 1 ];
}
// use this if you want to handle -ve numbers as well
public static function formatAny(n:Number, minimumLength:int):String {
return (n < 0 ? '-' : '') + formatAny(n, minimumLength);
}
How about this:
public static function format(n:int, len:int):String {
var v:String = n.toString();
return (v.length >= len) ? v : String(Math.pow(10, len) + n).substr(1);
}
There is not built-in function to do this btw. If you need decent padding functions, take a look at the StringUtils in Apache Commons Lang.
Props to dirkgently and all others who have responded here, but apparently people are voting up without actually trying the code.
dirkgently's final function is mostly correct, but his '>' needs to be a '<'.
This function performs as desired (tested fairly thoroughly):
public static function format(n:int, minimumLength:int):String {
var v:String = n.toString();
var stillNeed:int = minimumLength - v.length;
return (stillNeed < 0) ? v : String(Math.pow(10, stillNeed) + v).substr(1);
}
"If anybody wants to post some
extremely short equivalent in some
other language, that would be fun too."
In javascript it is easy - paste this into your browser's address bar
javascript: function zit(n, w) {var z="000000000000000000"; return (z+n).substr(-w);} alert(zit(567, 9)); void(0);
I've always done this by taking a string that is the maximum padded width of zeros containing all zeros, then appeneding the string to padded to the end of the zeros string and then using substring to get the right hand Length digits.
Something like:
function pad(num:int, length:unit):String{
var big_padded:String "0000000000000000000000000000" + num.toString();
return big_padded.substring(big_padded.length - length);
}
The as3corelib package put out by adobe has a nice little NumberFormatter class that uses a series of STATIC classes. In this case you could use the addLeadingZero function.
//The following method is from the NumberFormatter class of the as3corelib package by Adobe.
public static function addLeadingZero(n:Number):String
{
var out:String = String(n);
if(n < 10 && n > -1)
{
out = "0" + out;
}
return out;
}
I included the function just to show it's simplicity, but I would use the package instead of yoinking the function because it provides many other useful features like StringUtils, encryption methods like MD5, blowfish, etc.
You can download the package here
For newer users you must provide a classpath to where this package lives. It is also smart to import the classes instead of using their fully qualified class names.
private function leadingZeros(value:int, numDigits:int):String
{
return String(new Array(numDigits + 1).join("0") + String(value)).substr(-numDigits, numDigits);
}