Author Topic: Looping a function  (Read 3166 times)

How do I loop a function?
I can't seem to figure it out!

Code: [Select]
function loop(%code, %delay)
{
   eval(%code);
   schedule(%delay, 0, 'loop', %code, %delay);
}

I think that should work just fine



Disclaiming disclaimer:
eval() well execute whatever command you put into it, and can be potentially hazardous if used incorrectly.  Be ablsolutely sure any code including eval is idiot proof and will not cause unintended functions to be called.
« Last Edit: November 19, 2011, 01:56:38 PM by Nexus »

I think that should work just fine
Not quite, that'll eventually cause a crash because the schedules don't delete properly or something like that.

Anyway, you just need to cancel your schedule at the beginning of the function.
Code: [Select]
function loop(%code, %delay)
{
   cancel($MySchedule);
   eval(%code);
   $MySchedule = schedule(%delay, 0, 'loop', %code, %delay);
}

Code: [Select]
function loop(%code, %delay)
{
   eval(%code);
   schedule(%delay, 0, 'loop', %code, %delay);
}

I think that should work just fine

Please don't use eval, except as a very last resort. It greatly increases the chance of unintentionally creating a security flaw.

Also, please don't loop like that, as that loop will NEVER stop until you close the game entirely. Put the schedule inside the function that actually loops, so that you can at least decide to stop looping within that function. Generally, you want to stop looping when the server closes, at the very least...

Something like
Code: [Select]
function myLoopingFunction(%args, %are, %great)
{
    if(shouldStopLoopingNow())
    {
        return;
    }

    ... code ...

    schedule(someDelay, 0, myLoopingFunction, %args, %are, %great);
}

is both more secure, and can be stopped without redefining loop() to not loop anymore.

...
Anyway, you just need to cancel your schedule at the beginning of the function.
...

Canceling the schedule helps only by ensuring that you only have one loop running at a time, rather than one loop for every time it was started, all running at once.

Of course, that is unless you also cancel it somewhere else as well, as some sort of cleanup.

Not quite, that'll eventually cause a crash because the schedules don't delete properly or something like that.
The reason for cancelling a schedule at the start of a periodic function like that is to prevent multiple loops from being created if the function is executed more than once.

Please don't use eval, except as a very last resort. It greatly increases the chance of unintentionally creating a security flaw.
This is entirely false.

Please don't use eval, except as a very last resort. It greatly increases the chance of unintentionally creating a security flaw.
It's only an issue if the client has some sort of way to directly change what is eval'd, and you don't do anything to prevent the exploit

But in this case eval isn't necessary

This is what I use
Code: [Select]
function ServerCmdTestLoop(){
//Stuff
schedule(33,0,ServerCmdTestLoop);
}

Please don't use eval, except as a very last resort. It greatly increases the chance of unintentionally creating a security flaw.

This is a function to loop an ambiguous function.  It is much more useful than your version.  I should have included something to stop the loop, but I typed it up in like 20 seconds.


Anyway, you just need to cancel your schedule at the beginning of the function.

Then it defeats the purpose of having a universal function looper if it doesn't support multiple simultaneous looping functions.  However, in most cases that is correct.

Edit:  Thinking this over some more, I am not sure if having a schedule not parented to an object or variable is a good idea.  I might do something like %loop = schedule(hocus pocus); then send that as an argument to have cancelled.  Or wait that would mean %loop = schedule(%delay, 0, %code, %delay, %loop); and you can't send the schedule in that schedule.  Damn this is odd.  So I would have a loopingSO and have like loopingso.loop[%id] and I could just send the ID and omg this is suprisingly complicated.


This is what I use
Code: [Select]
function ServerCmdTestLoop(){
//Stuff
schedule(33,0,ServerCmdTestLoop);
}
Yea you just need something to stop the loop and you should be just fine with that.  Probably just a simple
Code: [Select]
if(!$islooping)return; should work fine.
« Last Edit: November 17, 2011, 09:52:31 PM by Nexus »

Let me count the fails here:

  • function loop

Name is far too generic, function far too specific, likely to cause conflicts with other mods. But if you rename it to something less collision-friendly, then why write a generic function at all?

  • eval(%code);

Unless you can prove that %code can never contain an exploit, you shouldn't use it. If you don't have the experience required to make such a guarantee, you shouldn't use it, in case you are wrong. Suggesting the use of eval() to anyone less than an extremely experienced coder is sharing a bad practice and encouraging exploitable code. And even they can make mistakes...

  • $MySchedule

Global, potential name conflict, though as long as you don't call it something like $test, shouldn't be a problem.

  • universal function looper

A universal function looper only needs call(). What you have is a universal code looper. Also, that universal part? It's more universal than you seem to believe. What if I wrote my own copy of loop() that took an extra parameter of how many times to run? Then whichever add-on was loaded last overwrites the other version. Suddenly my "loop 5 times, 10 seconds apart" calls become "loop infinite times, 10 seconds apart, until the game is closed". Or your "loop endlessly" calls happen 0 times. If you are lucky, I wrote my version to treat "" as "unlimited", and mine was loaded last, so nothing breaks.


The big problem here is encouraging the use of dangerous code without ever mentioning that it can be dangerous at all, and when/why. Oh, and then giving it out as an answer to copy/paste to someone who is likely to be new enough to coding that they don't realize that that sort of code can even BE dangerous.

Oh, and, due to an eval exploit in an add-on that I shall not name until the creator has fixed it, I literally could write a virus. Imagine if anyone joining your server while you have a certain add-on enabled can execute arbitrary code, infecting the server. Next time you join a server afterwards, you'll automatically try to infect the server the same way you were infected previously. This is because somebody who clearly understood what they were doing missed a single very obscure code path that bypassed their otherwise working filter system, so that malicious code made it into an eval() call intact.

Oh, and note that the only reason that the exploit in question works is that the coder decided to implement a form of reflection through eval, to make their code all nice and elegant and stuff. They could easily have written a few ugly but completely safe functions that didn't use eval, and replaced the eval lines with them. Do you choose to risk it? I wouldn't, as there are undoubtably others who can find that same flaw, and they might choose to exploit it, rather then report it.

Let me count the fails here:

  • $MySchedule

Global, potential name conflict, though as long as you don't call it something like $test, shouldn't be a problem.
Are you kidding me? If you don't even realize that that's just an example...

Who are you by the way? Your avatar is very familiar.


You are a moron.  Please leave this thread immediately.


No, I just happen to fully understand the importance of properly educating less experienced coders. You should never tell someone who has just started writing C to use gets(), for example, as you would be telling them that they should make their code exploitable and easy to crash, when given unexpectedly long input lines.

Giving bad advice ("Use eval!", without mentioning the dangers) is a sign that you are either intentionally trying to mislead them so that they never make any mods to compete with your own, or it shows that you don't understand how to teach others properly.


Specifically in this thread, you gave a snippet of code that, clearly, you were proud about having devised yourself, since it clearly solved the person's problem. Except, you didn't put the time in to explain how to use it, any drawbacks, or, really, how it supposedly solves their problem! First, you assume that they know that eval takes a string of code. Imagine their surprise if they end up getting a syntax error once per second as soon as they try to loop(myFunc, 1000); Or worse, loop(myFunc, 1); /*That is one second, right?*/. So, assuming they understand that eval takes a string and that schedule measures in thousandths of a second, and that eval executes code, so they'll need to add brackets and a semicolon, why would they need to ask the question in the first place?

Oh, and what if they were asking about recursion, rather than looping over time? Less likely, but entirely plausible, from their less-than-perfectly-clear phrasing?

So, your response is to give an overgeneralized solution that you are too proud of to accept any sort of criticism, and that you feel can solve any problem. A function so well thought out that nobody could possibly need an explaination for how it works. A function that will doubtlessly be copy-pasted into numerous other add-ons, with the same exact name. Oh, and then someone modifies it. Gasp! But why? It's clearly a perfect function, there is no reason at all possible that would cause somebody to ever edit it!

Except someone does. And then everyone who downloads it and any other add-on that uses your function get to experience the joys of subtle version incompatibilities!


If you share code, you must take the responsibility to ensure that it's recipients understand how it works. Otherwise, you are irresponsibly subjecting countless people playing to numerous bugs because somebody took your code and broke it because they didn't understand it.



Jesus, its like an autistic kid with insecurities about his intelligence learned to script.


Don't use eval?

My brief example code has bad namespace?

Never use recursion accomodate for more types of input?


These are all examples of terrible advice.  Ever heard of a default function called messageboxyesno(%title, %text, %yes, %no)  ?
Guess what it does!
eval(%yes); and eval(%no);
Hundreds of blocklanders die every day because of the dangerous side effects of using such a wild and exploitable functions.  Very Tragic.
Do not waste your time on such large paragraphs, no one respects will respect what you have to say about coding after this.
« Last Edit: November 19, 2011, 01:47:40 PM by Nexus »

Lol a lot of people in this thread don't know what they are talking about.

Here it is, lol:

function loopThing(%arg1,%arg2,%arg3)
{
     if(isEventPending($loopThing))
     {
          cancel($loopThing);
     }

     //code here

     $loopThing = schedule(milliseconds, 0, loopThing, %arg1, %arg2, %arg3);
}


To stop it, use the cancel function.

cancel($loopThing);
« Last Edit: November 17, 2011, 11:57:21 PM by Superb »


Actually you're just a moron eager to flaunt some information you've picked up but misinterpreted. You aim only to make yourself look supreme by bashing examples posted by others that supposedly contain flaws that you also committed in the examples you posted. You're not helping the poster of the thread at all.