How to dynamically generate variables in Action Script 2.0 - actionscript

I have a for loop in action script which I'm trying to use to dynamically create variable.
Example
for( i = 0 ; i &lt 3 ; i++)
{
var MyVar+i = i;
}
after this for loop runs, i would like to have 3 variables named MyVar1, MyVar2, MyVar3. I know the code above will give you a syntax error, but that is just to illustrate what I am trying to do. Any takers?
The primary reason i'm doing this is because I'm having scope problems noted here in this other unanswered Action Script question: How to pass variables into inline functions in Action Script 2
Thanks!

I could be wrong (I haven't done AS2 for a long while), but I think you can do this using array syntax:
for( i = 0 ; i < 3 ; i++)
{
this["myVar"+i] = i;
}
and then for variable access:
var foo = this["myVar0"] //etc

First answer is correct, but if you make the class dynamic (ie. new members can be created dynamically) ...
dynamic class ClassName { // etc. }
... then you can reference the variable in normal syntax:
var foo = this.myVar0;
You won't be able to access the variable at all without 'this' whether the class is dynamic or not.

Related

Can someone explain to me how this code works? Closure in Dart

I can't understand how the closure works in Dart. Why does BMW stay? This explanation causes my neurons to overheat. A lexical closure is a functional object that has access to variables from its lexical domain. Even if it is used outside of its original scope.
`void main() {
var car = makeCar('BMW');
print(makeCar);
print(car);
print(makeCar('Tesla'));
print(car('Audi'));
print(car('Nissan'));
print(car('Toyota'));
}
String Function(String) makeCar(String make) {
var ingane = '4.4';
return (model) => '$model,$ingane,$make';
}`
Console
Closure 'makeCar'
Closure 'makeCar_closure'
Closure 'makeCar_closure'
Audi,4.4,BMW
Nissan,4.4,BMW
Toyota,4.4,BMW
Calling car('Audi') is equal to calling (makeCar('BMW'))('Audi');
A lexical closure is a functional object that has access to variables from its lexical domain. Even if it is used outside of its original scope.
in simple english:
String make will stay valid as long as the returned function is not out of scope because the returned function has reference to String make.
In essence, you "inject" information needed for the newly created function. Your car knows that make is "BMW"
I think I figured it out. Here is an example where I left comments. Maybe it will help someone.
void main() {
var pr = funkOut(10); // assign a reference to an object instance
// of the Function class to the pr variable. pr is a closure because
// it is assigned a reference to an instance that contains a lexical
// environment (int a) and an anonymous function from this environment.
// 10 transfer to a
print(pr(5)); // 5 transfer to b //15
print(pr(10)); // 10 transfer to b //20
pr = funkOut(20);// 20 transfer to a
print(pr(5)); // 5 transfer to b //25
print(pr); // Closure: (int) => int
}
Function funkOut(int a) {
return (int b) => a + b;
}

How to modify a functions internal variables at runtime and pass it to another function?

Functions in Dart are first-class objects, allowing you to pass them to other objects or functions.
void main() {
var shout = (msg) => ' ${msg.toUpperCase()} ';
print(shout("yo"));
}
This made me wonder if there was a way to modify a function a run time, just like an object, prior to passing it to something else. For example:
Function add(int input) {
return add + 2;
}
If I wanted to make the function a generic addition function, then I would do:
Function add(int input, int increment) {
return add + increment;
}
But then the problem would be that the object I am passing the function to would need to specify the increment. I would like to pass the add function to another object, with the increment specified at run time, and declared within the function body so that the increment cannot be changed by the recipient of the function object.
The answer seems to be to use a lexical closure.
From here: https://dart.dev/guides/language/language-tour#built-in-types
A closure is a function object that has access to variables in its
lexical scope, even when the function is used outside of its original
scope.
Functions can close over variables defined in surrounding scopes. In
the following example, makeAdder() captures the variable addBy.
Wherever the returned function goes, it remembers addBy.
/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(int addBy) {
return (int i) => addBy + i;
}
void main() {
// Create a function that adds 2.
var add2 = makeAdder(2);
// Create a function that adds 4.
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
In the above cases, we pass 2 or 4 into the makeAdder function. The makeAdder function uses the parameter to create and return a function object that can be passed to other objects.
You most likely don't need to modify a closure, just the ability to create customized closures.
The latter is simple:
int Function(int) makeAdder(int increment) => (int value) => value + increment;
...
foo(makeAdder(1)); // Adds 1.
foo(makeAdder(4)); // Adds 2.
You can't change which variables a closure is referencing, but you can change their values ... if you an access the variable. For local variables, that's actually hard.
Mutating state which makes an existing closure change behavior can sometimes be appropriate, but those functions should be very precise about how they change and where they are being used. For a function like add which is used for its behavior, changing the behavior is rarely a good idea. It's better to replace the closure in the specific places that need to change behavior, and not risk changing the behavior in other places which happen to depend on the same closure. Otherwise it becomes very important to control where the closure actually flows.
If you still want to change the behavior of an existing global, you need to change a variable that it depends on.
Globals are easy:
int increment = 1;
int globalAdder(int value) => value + increment;
...
foo(globalAdd); // Adds 1.
increment = 2;
foo(globalAdd); // Adds 2.
I really can't recommend mutating global variables. It scales rather badly. You have no control over anything.
Another option is to use an instance variable to hold the modifiable value.
class MakeAdder {
int increment = 1;
int instanceAdd(int value) => value + increment;
}
...
var makeAdder = MakeAdder();
var adder = makeAdder.instanceAdd;
...
foo(adder); // Adds 1.
makeAdder.increment = 2;
foo(adder); // Adds 2.
That gives you much more control over who can access the increment variable. You can create multiple independent mutaable adders without them stepping on each other's toes.
To modify a local variable, you need someone to give you access to it, from inside the function where the variable is visible.
int Function(int) makeAdder(void Function(void Function(int)) setIncrementCallback) {
var increment = 1;
setIncrementCallback((v) {
increment = v;
});
return (value) => value + increment;
}
...
void Function(int) setIncrement;
int Function(int) localAdd = makeAdder((inc) { setIncrement = inc; });
...
foo(localAdd); // Adds 1.
setIncrement(2);
foo(localAdd); // Adds 2.
This is one way of passing back a way to modify the local increment variable.
It's almost always far too complicated an approach for what it gives you, I'd go with the instance variable instead.
Often, the instance variable will actually represent something in your model, some state which can meaningfully change, and then it becomes predictable and understandable when and how the state of the entire model changes, including the functions referring to that model.
Using partial function application
You can use a partial function application to bind arguments to functions.
If you have something like:
int add(int input, int increment) => input + increment;
and want to pass it to another function that expects to supply fewer arguments:
int foo(int Function(int input) applyIncrement) => applyIncrement(10);
then you could do:
foo((input) => add(input, 2); // `increment` is fixed to 2
foo((input) => add(input, 4); // `increment` is fixed to 4
Using callable objects
Another approach would be to make a callable object:
class Adder {
int increment = 0;
int call(int input) => input + increment;
}
which could be used with the same foo function above:
var adder = Adder()..increment = 2;
print(foo(adder)); // Prints: 12
adder.increment = 4;
print(foo(adder)); // Prints: 14

Scoping classes created in Lua using Luabind

I am aware that Lua classes can be created using the OO system that Luabind exposes to Lua:
http://www.rasterbar.com/products/luabind/docs.html#defining-classes-in-lua
class 'lua_testclass'
function lua_testclass:__init(name)
self.name = name
end
function lua_testclass:print()
print(self.name)
end
a = lua_testclass('example')
a:print()
However I am unable to figure out how to scope the class within another namespace so I can do the following:
a = MyScope.lua_testclass('example')
a:print()
Anyone has a idea. I do not want my classes to pollute the global namespace in Lua.
Luabind's class function will always pollute the global table. However, you can clean up after it:
function newclass(name)
oldglobal = _G[name]
class(name)
cls = _G[name]
_G[name] = oldglobal
return cls
end
Then you would use it like this:
MyScope.lua_testclass = newclass 'lua_testclass'
Analogous to local mod = require 'mod' you have to spell the name of the class twice, but you could easily build another function on top of this that could be used like setclass(MyScope, 'lua_testclass'), automatically putting the class into MyScope:
function setclass(scope, name) scope[name] = newclass(name) end
Disclaimer: All this code is entirely untested.
I did mine a little differently, but it's generally the same concept. Mine doesn't create the class, but rather just moves it. I also implemented it on the C++ side.
To implement what I did in Lua, you would write:
function moveClass(name)
oldGlobal = _G[name]
_G[name] = nil
return oldGlobal
end
To implement it in C++, you would write:
luabind::module(lua) [
luabind::def("moveClass", +[](lua_State * lua, std::string name) {
// In the case the class does not exist, this will just
// remove nil and return nil. That essentially does nothing.
luabind::object oldGlobal = luabind::globals(lua)[name];
luabind::globals(lua)[name] = luabind::nil;
return oldGlobal;
})
];
So now if you were to use that to move a class you created, you would do this:
class 'MyClass'
myTable = {}
myTable.MyClass = moveClass 'MyClass'
As an extra note, if you want the moveClass function to give an error in the case that the class you are trying to move does not exist, use luabind::type(oldGlobal) == LUA_TNIL to determine if the class existed or not.
Example:
luabind::module(lua) [
luabind::def("moveClass", +[](lua_State * lua, std::string name) {
luabind::object oldGlobal = luabind::globals(lua)[name];
if (luabind::type(oldGlobal) == LUA_TNIL) {
throw std::runtime_error("Class does not exist.");
}
luabind::globals(lua)[name] = luabind::nil;
return oldGlobal;
})
];

using concatenation in getUrl during loop?

I would like to write Actionscript loop that involves "getURL". However, from what I can see getURL does not allow concatenation of variable names?
I have variables textholder0, textholder1, textholder2 that have movieclip names as values and link0, link1, link2 that have website addresses as values.
I can use this["textholder" + 0].onRelease but getURL("link"+ 0) gives "undefined"
textholder0.onRelease = function()
{
getURL(link0);
}
textholder1.onRelease = function()
{
getURL(link1);
}
textholder2.onRelease = function()
{
getURL(link2);
}
Any way to do this so I can create a loop for the above?
Here is a test. Unfortunately, it still gives me "undefined/" for the URL. To keep it simple I created three movie clips, with instances textholder0, textholder1, textholder2. Put a loop on the main timeline.
var links:Array = ["http://www.google.ca", "http://www.google.com", "http://www.google.ru"];
for(var i:Number=0; i<links.length; i++){
this["textholder" + i].linkURL = links[i];
this["textholder" + i].onRelease = function() {
getURL(linkURL);
}
}
Here is output from debugger window
Variable _level0.links = [object #1, class 'Array'] [
0:"http://www.google.ca",
1:"http://www.google.com",
2:"http://www.google.ru" ]
Variable _level0.i = 3
Movie Clip: Target="_level0.textholder0"
Variable _level0.textholder0.linkURL = "http://www.google.ca"
Variable _level0.textholder0.onRelease = [function 'onRelease']
Movie Clip: Target="_level0.textholder1"
Variable _level0.textholder1.linkURL = "http://www.google.com"
Variable _level0.textholder1.onRelease = [function 'onRelease']
Movie Clip: Target="_level0.textholder2"
Variable _level0.textholder2.linkURL = "http://www.google.ru"
Variable _level0.textholder2.onRelease = [function 'onRelease']
I am starting to think that you can not use onRelease within a loop at all.
getURL("link"+ 0) will try to go to a URL "link0", since "link"+ 0 will be concatenated to the string "link0", and not get the value of link0. But you can try doing this:
getURL(this["link" + 0]);
The difference, and the mechanism of the bracket notation, is that you can reference a property of an object in two ways - using dot notation, like this.link0, or the bracket notation, this["link0"]. But it has to be expressed as an object property, just saying "link" + 0 anywhere, like in getURL("link"+ 0) won't give a reference to link0.
ok, so I think the problem with the loop here is that it was incrementing "i" variable before any of the buttons were clicked.
http://www.senocular.com/flash/tutorials/faq/#loopfunctions
Senocular.com says "you need to define a new, unique variable to represent that value at the time of function creation and have the function reference that value"
So the loop goes as following
var links:Array = ["http://www.google.ca", "http://www.google.com", "http://www.google.ru"];
var curr_button;
for(var i=0; i<=links.length; i++){
curr_button = this["textholder"+i];
//note creation of an extra variable "num" below to store the temp number
curr_button.num = i;
curr_button.onRelease = function() {
getURL(links[this.num]);
}
}

Is there a better way to get hold of a reference to a movie clip in actionscript using a string without eval

I have created a bunch of movie clips which all have similar names and then after some other event I have built up a string like:
var clipName = "barLeft42"
which is held inside another movie clip called 'thing'.
I have been able to get hold of a reference using:
var movieClip = Eval( "_root.thing." + clipName )
But that feels bad - is there a better way?
Movie clips are collections in actionscript (like most and similar to javascript, everything is basically key-value pairs). You can index into the collection using square brackets and a string for the key name like:
_root.thing[ "barLeft42" ]
That should do the trick for you...
The better way, which avoids using the deprecated eval, is to index with square brackets:
var movieClip = _root.thing[ "barLeft42" ]
But the best way is to keep references to the clips you make, and access them by reference, rather than by name:
var movieClipArray = new Array();
for (var i=0; i<45; i++) {
var mc = _root.thing.createEmptyMovieClip( "barLeft"+i, i );
// ...
movieClipArray.push( mc );
}
// ...
var movieClip = movieClipArray[ 42 ];
You can use brackets and include variables within them... so if you wanted to loop through them all you can do this:
for (var i=0; i<99; i++) {
var clipName = _root.thing["barLeft"+i];
}

Resources