Fog Creek Software
Discussion Board




Static variables - good, bad, or just plain ugly?

Imagine that you have a method in your class which can be called from a loop outside of your code. For whatever reason, your method needs to know how many times it has been called for this particular object, so you decide to have a variable to count this fact. Member variable or static variable in the method?

As far as I can see the latter is better because it keeps the visibility of the counter to only the code which is interested in it (i.e. the method in question), but I have this nagging "that's just soooo dirty!" feeling that I can't shake.

The problem might go away because it is possible that I will refactor and take the method out into a class of its own, but then again I might not and so it might not.

Any ideas, comments, whatever?


Monday, September 15, 2003

I would just bite the bullet and have a private member variable in the class, say cnt_fooBar and initialize it to 0 when the object gets created.

Patrik
Monday, September 15, 2003

I use this for UIDs etc all the time.  Sometimes effective things are ugly.

"Perfection is when there is nothing left to remove" [who said that?  someone famous I'm sure..]

i like i
Monday, September 15, 2003

Hi insertnamewithheldhere,

the fact that you need to 'know how many times it has been called for this particular object' means it can never be a static variable.  They refer to the class and not any specific instance. 

Unless you really intended 'this particular class', in which case a static var still sounds risky.  What if you need multi-threading?

Waving and Drowning
Monday, September 15, 2003

oops,

thinking in a language that doesn't allow static method vars, only static class ones.

Waving and Drowning
Monday, September 15, 2003

anon,

Are we talking about VB statics here.

I think VB statics are one of the most underused features of VB.

In the code I maintain there are dozens of private class variables that only get referenced in one function.  They should be static in that method, rather than cluttering up the class declaration.

The rule is to keep the visibility of a variable to the minimum possible.  In VB static helps you to do this.

Ged Byrne
Monday, September 15, 2003

A private counter will tell how many times this method has been called  for that instance of the class. Static counter will calculate all calls of that method for all* instanses of that class.

Evgeny Gesin /Javadesk/
Monday, September 15, 2003

Ged - no, I'm using C++, but the principle is the same.

Heh. It seems opinions are divided, but at least most of you have made your minds up whereas I am still having an inner debate!


Monday, September 15, 2003

I'd use a member variable. Using a static means:

You can never reset the counter.
You can never access it from outside the function.

That, and I've never seen a function-scope static that wasn't a hack.

Mr Jack
Monday, September 15, 2003

"Using a static means:

You can never reset the counter."

Never need to.

"You can never access it from outside the function."

This is a positive AFAIAC. The point is that the variable is really only of interest to this particular aspect of the object, which is why I am considering the static vs member variable argument.

"That, and I've never seen a function-scope static that wasn't a hack"

That's what worries me, too :-)  What I am not sure is what, if anything, this is really a hack for. I think I am going to sleep on it and see what shape it looks tomorrow.


Monday, September 15, 2003

I haven't really seen any justification for why you'd want it to be static.  Having a member variable that gets incremented does what you want without any potential side-effects (other methods calling earlier or later, different threads calling, etc.).

The only reason I could think why you'd want static is that you have to instantiate a new instance with each iteration of the loop.  And if so, I'd wonder why.

So, my vote is member variable.  Statics are for universal, lifetime access, which is not what you described.

David
Monday, September 15, 2003

You don't want to access it from outside _now_.
You don't want to reset the counter _now_.

Making it static makes it harder to change later if you do want these things. Without knowing what you're trying to do it's hard to give meaningful recommendations though.

Mr Jack
Monday, September 15, 2003

<BLOCKQUOTE>You don't want to access it from outside _now_.
You don't want to reset the counter _now_.

Making it static makes it harder to change later if you do want these things.</BLOCKQUOTE>

Why is it harder? Taking a static variable and making it a member variable takes about 5 seconds?

Groby
Monday, September 15, 2003

The reason its hard is that along the way you add code that assumes the characteristic of a static variable.  Being static means that you are visible to all instances of a class.  As you code, or someone else codes, they will decide to exploit the dependencies that you've defined within the class.  Then comes the day when you decide you will instantiate more than one instance of that class, and you'll have all sorts of dependencies based on the static member.

Static members should have distinct purpose.  Classic examples are factory methods and callbacks.  But even in these methods there is a unique context (refering to the class instance) being addressed.  Adding static members without specific reasons is sloppy coding and should be avoided.

nat ersoz
Monday, September 15, 2003

"Being static means that you are visible to all instances of a class."

Since we were talking about a static variable in a member function, it's only visible in that function. Important distinction, because it limits dependencies.

"As you code, or someone else codes, they will decide to exploit the dependencies that you've defined within the class."

A problem, unless they're required to write a test to document it.

"Then comes the day when you decide you will instantiate more than one instance of that class, and you'll have all sorts of dependencies based on the static member."

I /really/ fail to see how that can happen if it's static within the function scope. Example would be greatly appreciated.

"Adding static members without specific reasons is sloppy coding and should be avoided."

As far as I recall, we wanted to count how often a function was invoked. That seems pretty specific to me.  I don't get why we don't need to see that count outside the function, but as long as we don't a static counter seems perfectly appropriate....

- Robert

Groby
Monday, September 15, 2003

#include <stdio.h>

class test
{
public:
    test( void ) {};

    void svar( void )
    {
        static int count;
        count += 1;
        printf( "svar: %d\n", count );
    }
};

int main( int argc, char **argv )
{
    test
        x, y;

    x.svar();
    y.svar();

    return 0;
}


Output:
svar: 1
svar: 2

Which means that the static var count inside test::svar() is incremented when each instance of class test calls svar().  Is this the behavior you want (I would likely not).  It is not the same as if count were private to the class.

nat ersoz
Monday, September 15, 2003

Gads, the more I think about it, the more abhorent this code is.  Part of a good class declaration is that you should be able to infer the operational behavior of the class from the declaration only.  The guts  (definition, i.e. method implementation) should not require parsing by the user of the class.

But here, the potential user has no idea that the static var count is counting all instance calls to some method.  If the count var were static within the class declaration, then at least the client would have a clue.  But not here.

This is bad practice anyway you cut it.

nat ersoz
Monday, September 15, 2003

I guess "your method needs to know how many times it has been called for this ****particular object****.... "
does not leave you any options except normal member variable. Either stitic in function or static member variable will not work in such a case.
If you want to make it little safer for outer world you may use #ifdef MY_SPECIAL_TRACKING and define it only for your debug/non-public builds.

Is your request actually "I need to profile this code but I don't have profiler that will do what I want"? In this case you may try to factor out profiling code into some class and use it in some nice way...

WildTiger
Monday, September 15, 2003

Nat, what I was trying to say is:

If we want to count all calls to that function, regardless of instance, than a static member is probably one of the better choices. The only alternative is a static class member, so we need to decide what visibility we want.

I know that it won't work for a per-instance count - obviously. I'm just saying there's nothing wrong with a static if it is the right tool. And sometimes, it is.

Statics in member function tend to be debug-things. At least for me. Oftentimes, I don't WANT to expose them to the world.

Groby
Monday, September 15, 2003

The person who said "Perfection is attained not when there is nothing left to add but when there is nothing left to take away" was Antoine de Saint-Exupery, author of "Le petit prince".

Gareth McCaughan
Monday, September 15, 2003

Sorry, my over-reaction...  a pet peeve...

nat ersoz
Tuesday, September 16, 2003

"Static members should have distinct purpose"

It would do. The object is very short lived and is really only a kind of.. umm.. well I don't know what you call it. The point of it is to stop the main classes in the app having too many dependencies on each other (the reasoning is a bit more involved than that and I don't think what I have written really gives a decent description, but I can't spend too much time here). If there was an indirection pattern I guess it would apply to this class.

"Part of a good class declaration is that you should be able to infer the operational behavior of the class from the declaration only"

Agreed.

"The guts  (definition, i.e. method implementation) should not require parsing by the user of the class."

Or indeed private member methods or variables.

But carry on, you're convincing me, if somewhat slowly :-)


Tuesday, September 16, 2003

Maybe I can make it clearer.

The method must be called one or many times to complete the operation (caller does not know how many times, only whether the operation is complete or not - I'm stuck with this behaviour because of the framework). The method needs to know "where it is" in the operation, hence the need for a counter of some sort. When it is complete both it and its caller will know this fact, therefore a static in the method could be reset to zero when the method completes the final run.


Tuesday, September 16, 2003

Definetely use a member variable. What you are describing there is object state. Object state should _always_ be a member variable.

Mr Jack
Tuesday, September 16, 2003

Member variables contain object state.
Static member variables contain class state.
Static local variables contain local method state.

Just pick the appropriate implementation.

PS: Stateful methods are non-reentrant and require synchronization.

Dino
Tuesday, September 16, 2003

You might also want to look at the State pattern in the GoF book (_Design Patterns_, Gamma et. al.) for an alternative approach.

The basic idea is that you have a class per state, and then the "master" class swaps out the state class as it moves from state to state. Allows you to get a lot more information than just a counter into your state information, and very easy to change around as your requirements change.

Chris Tavares
Tuesday, September 16, 2003

*  Recent Topics

*  Fog Creek Home