views:

567

answers:

7

I often want to trigger a certain function just once, but I need to trigger it from within another function that gets repeatedly called. For instance, taking a snapshot of something for later use. I usually do it by setting a global boolean.

I'm wondering whether the way I do it is actually best way?

I seem to recall reading that global variables are bad, and global boolean variables are even worse!

Anyway, this is how I usually accomplish triggering a certain method just once:

In my initial set of variables...

private var myStatus:Boolean = false;

Then, within the function that gets called often...

if (!myStatus) {
    doMyFunction();
    myStatus = true;
}

It seems fairly logical to me, but is it the right thing?

UPDATE: Well, based on what I learned from your answers, instead of checking a global boolean variable, I now first check whether the XML node exists (I am storing the images within an XML structure before any writing to disk occurs), and, if it doesn't, then I append a new node with the base64 encoded image data. I do still set a boolean flag so that later on I can overwrite the blank image with user edited image data if need be. It works perfectly. Thank you all for your help!

I also now feel more comfortable about using that particular (thread unsafe) system in certain situations.

A: 

I see nothing wrong with your approach here. Keep in mind there isn't always the "Right" thing...there are definetly wrong things but what is right can be subjective, and can also depend dramatically based on the requirements of the system.

JoshBerke
A: 

I don't see any other way. The only thing that comes to mind about how to improve this is - thread safety. But that's only necessary if you have multiple threads calling the function.

Vilx-
+4  A: 

It really depends on precisely what you mean. If your code will be invoked from more than one thread, then you have a race condition which could mean that doMyFunction could be called many times. This is because more than one thread could check myStatus, see that it is false, then invoke doMyFunction. You can improve the situation a little bit by setting the variable first:

if (!myStatus) {
    myStatus = true;
    doMyFunction();
}

but that only narrows the window for problems, doesn't eliminate it.

To eliminate the race condition, you need a lock.

Ned Batchelder
Well, this particular instance is within a fairly procedurally designed Flex Application, although the if statement is within a case/switch statement that could conceivably be called twice if there was serious net congestion. I will definitely move the variable setter up. Thanks!
defmeta
+2  A: 

It's not thread-safe. That might not matter to you, but you did say "language-agnostic": you probably wouldn't want to use this pattern in a general-purpose library for Java.

This is a hard question to answer in a language-agnostic way, because the available alternatives very much depend on language. For instance on POSIX you've got pthread_once if you need thread-safety. In C you've got static local variables to get that boolean out of the global scope. In any OO-language, if you're taking a snapshot of "something" for later use, then there might be a suitable object corresponding to the "something" (or to the snapshot), which could store the flag.

Steve Jessop
+4  A: 

In C/C++ you can usually keep the fact that doMyFunction() is called only once encapsulated by using a static variable like so:

void doMyFunction() {
     // gets called only once.
     // side effects go here.
}

void functionThatGetsCalledALot() {
    static bool called = false;
    if (!called) {
        doMyFunction();
        called = true;
    }
    // do more stuff
}

This avoids the use of globals but has the same effect, and the static var is declared right where it's relevant, so it's clear what's going on. Note that this isn't thread-safe, so you'll need a lock if you have threads.

tgamblin
+6  A: 

When you call a function it should do what you expect it to do with the arguments you give it. If you call a function twice in exactly the same way you should expect that function to give you the same results or do the same thing.

It is probably better to move this call-once dependency to the logic that calls your function many times. If you only need to call the function once then only call it once. Alternatively, pass different arguments to the function to indicate that you're doing something different.

rojoca
But what if the function returns the result of a case statement, and you wants one of the case statements to be able to run a function only the first time it is returned? Or am I still not getting it?
defmeta
@defmeta: I think he means consider why you're only running the code once. If it's to do setup, maybe you could simplify by moving the setup out to an earlier stage. If you're caching an expensive result that might never be needed, then sure, go ahead and do it on first use.
Steve Jessop
@defmeta: onebyone is right - maybe you could be a bit more specific on what your run-once function needs to do? Are there side-effects from calling this function? What happens if you do call it twice?
rojoca
The function saves an image of a blank shape that the user has chosen, it must only be called once because after the user has edited the shape it must not be overwritten with another blank. I do see that there are other ways of doing this, unfortunately time is not on my side!
defmeta
Perhaps your save image function could have a boolean overwrite argument which if true means you only save if no image (with the same name) exists already.
rojoca
You're spot on! See updated question...
defmeta
A: 

In Perl 5.10 or later, you would use a state variable.

use 5.010;

sub test{
  state $once = 1;

  if( $once ){
    $once = undef;
    say 'first';
  } else {
    say 'not first';
  }
}

test for 1..5;

outputs

first
not first
not first
not first
not first
Brad Gilbert