Graal Forums

Graal Forums (https://forums.graalonline.com/forums/index.php)
-   NPC Scripting (https://forums.graalonline.com/forums/forumdisplay.php?f=8)
-   -   An Intro to Anonymous Functions (https://forums.graalonline.com/forums/showthread.php?t=134259031)

WhiteDragon 05-03-2010 11:10 PM

An Intro to Anonymous Functions
 
This is something that I've been ranting about for awhile on the forums, so I'll be writing a little post to let everyone know about them.

Anonymous Function? What's that?

Usually, you see functions like this:
PHP Code:

function onCreated() {
}

function 
myExampleFunction() {
  return 
10;


These functions have names: onCreated and myExampleFunction.


However, an anonymous function has no name:
PHP Code:

function onCreated() {
  
temp.= function () {
    return 
10;
  };


Here, temp.f is not the function's name, it is just a pointer to it. You could easily do something like this
PHP Code:

function onCreated() {
  
temp.= function () {
    return 
10;
  };
  
temp.temp.f;


Now what is the function's name? Both temp.g and temp.f point to the same function.

This is why they are called "anonymous" functions.


To call an anonymous function, you need to do (@variable)();

Here is an example:
PHP Code:

function onCreated() {
  
temp.= function () {
    return 
10;
  };
  
temp.output = (@temp.f)();


After this runs, temp.output would equal 10.

Note: there reason for that crazy calling syntax is because of a bug where calling the function after doing certain things to it breaks. Doing it this way guarantees that it'll run. Help me ask Stefan if you want it fixed. ;-)




Is there anything different about anonymous functions besides not having a name?

The cool part about anonymous functions is that you can pass them to other functions.

For example:

Normal coding
PHP Code:

function onCreated() {
  
temp.something 10;
  
this.example(temp.something);
}
function 
example(temp.whatever) {
  echo(
temp.whatever);


Let's use anonymous functions!
PHP Code:

function onCreated() {
  
temp.something = function () {
    return 
10;
  };
  
this.example(temp.something);
}
function 
example(temp.whatever) {
  echo((@
temp.whatever)());



Now, this does absolutely nothing different from the first version except making you type more.

But it should be clear that you can pass around the function you create, then call it somewhere else.



So what do I use this for?

Separating your code into pieces (also known as abstraction), in order to get rid of duplicate code.



I'll just hit you right off the bat with an example:

One class, and two weapons...


Class: looper
PHP Code:

//#CLIENTSIDE
function onLoopIt(temp.ftemp.time) {
  (@
temp.f)();
  
temp.time temp.time 0.05;
  if (
temp.time 0) {
    
this.scheduleevent(0.05"LoopIt"temp.ftemp.time);
  }


Weapon: Slow Door
PHP Code:

this.join("looper");
//#CLIENTSIDE
function onWeaponFired() {
  
this.ball showimg(200"door.png"2020);
  
temp.= function () {
    
this.ball.+= 0.1;
  };
  
this.trigger("LoopIt"temp.f5);


Weapon: Fast Door

PHP Code:

this.join("looper");
//#CLIENTSIDE
function onWeaponFired() {
  
this.ball showimg(200"door.png"2030);
  
temp.= function () {
    
this.ball.+= 0.2;
    
this.ball.alpha random(0,1);
  };
  
this.looper("LoopIt"temp.f5);


Slow Door would show an image and move it for 5 seconds.
Fast Door would show an image and move it twice as fast, for 5 seconds, and PULSE LIKE CRAZY!

Yes, I just abstracted a timeout/scheduleevent out of my code. You can use this technique anywhere you want, to extract code from any portion of your script and store in a reusable form (such as a class).


If you want an exercise, start with the previous code, and make the looper call a function (which you would pass in) when it is done looping. That code could hide the ball, for example.





This alone is already very powerful, but it you can do even more with it come v6, and I'll write an article for that when it comes out.


Feel free to ask any questions.

benpoke103 05-03-2010 11:16 PM

I don't appreciate you negatively speaking about my good friend Door, but nice job nonetheless!

xAndrewx 05-03-2010 11:19 PM

I'll be honest with you, this is stupid and makes scripts even harder to read.

WhiteDragon 05-03-2010 11:22 PM

Quote:

Originally Posted by xAndrewx (Post 1573897)
I'll be honest with you, this is stupid and makes scripts even harder to read.

I'd guess that it's harder to read because you aren't used to it.

Maybe this will motivate it a little... rewrite the example I gave in the way you'd usually do yourself.

benpoke103 05-03-2010 11:33 PM

Quote:

Originally Posted by xAndrewx (Post 1573897)
I'll be honest with you, this is stupid and makes scripts even harder to read.

True honestly.

xAndrewx 05-03-2010 11:37 PM

Quote:

Originally Posted by WhiteDragon (Post 1573899)
I'd guess that it's harder to read because you aren't used to it.

Maybe this will motivate it a little... rewrite the example I gave in the way you'd usually do yourself.

HTML Code:

function onCreated() {
  this.ball = showimg();
 
  this.onMoveBall(0.05, 5);
}

function onMoveBall(timer, count) {
  this.ball.x += 5;

  if (temp.count > 0) {   
    scheduleevent(temp.timer, "MoveBall", temp.timer, (temp.count - 1));
  }
}

I understand you've got a function which means you don't need to keep repeating the same script, (which is good, don't get me wrong) but when a new scripter comes on to the server they won't understand that script.

I wouldn't use your script, as for me it just makes GScript more complicated than what it should be. :(
Sorry (it is good, but why not just do the loop inside the weapon using functions people can read!)

WhiteDragon 05-03-2010 11:48 PM

Quote:

Originally Posted by xAndrewx (Post 1573905)
but when a new scripter comes on to the server they won't understand that script.

When a new scripter comes on to a server, they won't understand anything. People learn what is there.


Quote:

Sorry (it is good, but why not just do the loop inside the weapon using functions people can read!)
If it was just one weapon, I probably would, but chances are this pattern is going to be in multiple weapons, so it is best to not have duplicate code.


Quote:

I wouldn't use your script, as for me it just makes GScript more complicated than what it should be. :(
Okay.

coreys 05-03-2010 11:56 PM

My behavior trees would not have been possible without anonymous functions. :)

WhiteDragon 05-04-2010 12:08 AM

Quote:

Originally Posted by coreys (Post 1573913)
My behavior trees would not have been possible without anonymous functions. :)

Same with my GBench and QuickCheck.

Skyld 05-04-2010 12:12 AM

Quote:

Originally Posted by xAndrewx (Post 1573897)
I'll be honest with you, this is stupid and makes scripts even harder to read.

However, it makes it incredibly easy to create easy function interfaces, or to pass the same parameter set to a large number of functions at the same time. Anonymous functions are at first confusing but they can be useful, and also help to provide some JavaScript compatibility.

adam 05-04-2010 01:02 AM

It takes some getting used to, but I am very happy to have this this. There have been a few times where i might have found this very useful. I'll keep it in mind for the future.

xAndrewx 05-04-2010 09:06 AM

Quote:

Originally Posted by Skyld (Post 1573921)
However, it makes it incredibly easy to create easy function interfaces, or to pass the same parameter set to a large number of functions at the same time. Anonymous functions are at first confusing but they can be useful, and also help to provide some JavaScript compatibility.

Don't get me wrong, I think it's useful.
I don't like how it isn't named, I'd rather replicate the same function in each npc with a clear understanding to the reader what exactly is happening.


All times are GMT +2. The time now is 01:26 AM.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2025, vBulletin Solutions Inc.
Copyright (C) 1998-2019 Toonslab All Rights Reserved.