Posted by Dan
Fast on
June 24, 2009 under
Flash -
0 Comments
Lazy evaluation is a useful practice for any programmer who wants to cut down on unnecessary processing. There's no need to break it out if it's not necessary; especially if the language (Actionscript) is ill suited to it. There are cases though where delaying computation until the result is required lets lazy evaluation slice off the extra computational gristle that's slowing down my code.
I ran into a situation a few days ago that really benefited from the lazy approach. I had a class named Vector2 which handled 2-dimension computation, as described below.
//Vector2 with Eager Evaluation
public class Vector2 {
private var _x:Number;
private var _y:Number;
private var _length:Number;
public function Vector2( x:Number = 0, y:Number = 0 ) {
setXY( x, y );
}
public function setXY( x:Number, y:Number ):void {
_x = x;
_y = y;
_length = Math.sqrt( _x * _x + _y * _y ); //length is computed as soon as x and y are set
}
public function get x():Number {
return _x;
}
public function get y():Number {
return _y;
}
public function get length():Number {
return _length;
}
}
The issue arose when dealing with the _length value in a Vector2. The square root in determining the _length of a Vector2 was computationally intensive and often unnecessary. It was a rare occasion when I needed the length of a vector; most of the time I produced vectors for minor computations that never needed a calculation of length. Therefore, I wanted to delay the computation of the length of the vector until it was absolutely necessary.
Simultaneously, I didn't want a getLength() function, because I didn't want to have to recompute the length every time I asked for it. I wanted to compute the length once, the moment I asked for it, and save that result for future references. However, if in the future I changed the _x or _y, I needed some way to tell my program that the length of the vector needed to be recomputed the next time I requested it.
Lazy evaluation magically fulfills all my requirements.
Implementing Lazy Evaluation
Flash is an Eagerly Evaluated language though, how can one implement Lazy Evaluation?
//Vector2 with Lazy Evaluation
//Code not directly applicable to the example has been removed
public class Vector2 {
private var _x:Number;
private var _y:Number;
private var _length:Number;
private var lengthFunction:Function;
public function Vector2( x:Number = 0, y:Number = 0 ) {
_x = x;
_y = y;
lengthFunction = function() {
_length = Math.sqrt( _x * _x + _y * _y );
};
}
public function set x( newX:Number ):void {
_x = newX;
lengthFunction = function():void {
_length = Math.sqrt( _x * _x + _y * _y );
}
}
public function set y( newY:Number ):void {
_y = newY;
lengthFunction = function():void {
_length = Math.sqrt( _x * _x + _y * _y );
}
}
public function get x():Number {
return _x;
}
public function get y():Number {
return _y;
}
public function get length():Number {
lengthFunction(); //recomputes the length of the Vector2 if necessary
lengthFunction = function():void {} //replaces the length function with an empty function call
return _length;
}
}
The Vector2 class written above achieves lazy evaluation through Flash's Function class. When I request the length of my Vector2, the lengthFunction (an object of a function) is called, and the length is returned. The lengthFunction is where all the lazy magic happens.
Whenever the _x or _y value is altered, the lengthFunction is set to Math.sqrt( _x * _x + _y * _y ). Once the length is evaluated however, it reassigns itself to an empty function. Next time I ask for the length of my Vector2, the processor will run through an empty function call rather than the computationally intensive square root calculation.
This class uses a number of getter and setter methods which I have heard are rather slow, but that doesn't detract from the practical merit of this practice. It's like helping a friend move into a new apartment, you have to know when to avoid the unnecessary heavy lifting.
Posted by Ryan
Coyner on
May 25, 2009 under
Git -
0 Comments
Here is a good article on setting
up a new remote git repository. Here are additional steps to create a
shared repository which allows multiple users to contribute to the same
repository. First, add sharedrepository = 1 in the
config file of the repository:
[core]
repositoryformatversion = 0
filemode = true
sharedrepository = 1
Create a new system group for users who should have access to the
repository. Add the users into the group:
$ groupadd git
$ gpasswd -a ryan
Next, set up secure permissions on the repository. Start by changing the
ownership of the files in the repository to root and the group specified
above:
$ cd /var/git/project.git
$ chown -R root:git .
Remove access to the repository from everybody except the user and group:
chmod -R o-rwx .
The group should have the same permisisons as the user:
chmod -R g=u .
Add the s flag on the group permissions for all directories
in the repository. This will give processes that tries to access the
directories the necessary privileges to add and modify content within the directories.
This is necessary to allow multiple external users to commit to the
repository:
find . -type d | xargs chmod g+s
That's it. The repository should be set and good to go.
Posted by Dan
Fast on
April 13, 2009 under
Flash -
1 Comment
I have a confession to make - I've been seeing another language.
I'm sorry AS3, but Scheme is just so much more elegant that you.
I've decided to focus more on the functional aspects of AS3 after fooling around with Scheme for the last semester or so. All of what I'm about to say could be done with more explicit objects, but I think that would be masking the idea behind this code.
I'm working on a new game where a little man on a raft is hunted by God. God, in his old testament (and vaguely Zeusish) rage, hurls bolts of lightning, summons storms, and calls really enormous fish to smite this poor little dude. I wanted my lightning strikes to come in delayed intervals (first bolt at 1 second, second bolt at 3 seconds, etc... ), but I didn't want to explicitly call a timer every time. I wanted a more general solution to the problem. Then I found out that AS3 was pretty good at passing functions as objects.
Code
The following code sets up our example.
Cut and paste it into the timeline to run it.
//Create a new Sprite that is a child of the stage
Var testSprite:Sprite = new Sprite();
addChild( testSprite );
//draw a rectangle in the sprite
testSprite.graphics.beginFill( 0x0000FF, 1 );
testSprite.graphics.drawRect( 0,0, 200 200 ); //the function we're going to delay
testSprite.graphics.endFill()
Now we're going to delay the function call drawRect(...). Replace your previous code with the following.
The Function object has an .apply function, which takes the object the function is called on, and the arguments (in the form of an array) passed to that function.
//Create a new Sprite that is a child of the stage
Var testSprite:Sprite = new Sprite();
addChild( testSprite );
//draw a rectangle in the sprite
testSprite.graphics.beginFill( 0x0000FF, 1 );
//you'll notice that we're not calling the function, just passing its reference.
Var delayFunction:Function = testSprite.graphics.drawRect;
//the arguments provided for the function
var arguments:Array = [ 0, 0, 200, 200 ];
//a simple timer to delay the function call
var timer:Timer = new Timer( 1000, 1);
timer.addEventListener( TimerEvent.TIMER, runFunction );
timer.start();
//our function that listens to the timer, waiting for it to ring before running
protected function runFunction( event:Event ):void {
delayFunction.apply( testSprite.graphics, args );
testSprite.graphics.endFill()
}
Warnings about this method of programming. Make sure your object doesn't get dereferenced between when you create the function and when it gets applied (that should throw you some errors).
Now for the more general case. Here is a little class I programmed that delays function calls.
package {
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
/**
* Delays before running the function
* @author Daniel Fast
*/
public class WaitThenDo {
protected var timer:Timer;
protected var delayFunction:Function;
protected var args:Array;
protected var obj:Object;
/**
* delay a number of seconds before running the function
*/
public function WaitThenDo( func:Function, obj:Object, args:Array, delay:Number, repeat:Number = 1 ):void {
this.args = args;
this.delayFunction = func;
this.obj = obj;
timer = new Timer( delay * 1000, repeat );
timer.addEventListener( TimerEvent.TIMER, runFunction );
timer.start();
}
protected function runFunction( event:Event ):void {
delayFunction.apply( obj, args );
}
}
}