11

I would like to know if it is a good practice to generalize variables (use single variable to store all the values).
Consider simple example

 Strings querycre,queryins,queryup,querydel; 
    querycre = 'Create table XYZ ...';
    execute querycre ;
    queryins = 'Insert into XYZ ...';
    execute queryins ;
    queryup  = 'Update  XYZ set ...';
    execute queryup;
    querydel = 'Delete from XYZ ...';
    execute querydel ;

and

 Strings query; 
    query= 'Create table XYZ ... ';
    execute query ;
    query= 'Insert into XYZ ...';
    execute query ;
    query= 'Update  XYZ set ...';
    execute query ;
    query= 'Delete from XYZ ...';
    execute query ;

In first case I use 4 strings each storing data to perform the actions mentioned in their suffixes.
In second case just 1 variable to store all kinds the data.
Having different variables makes it easier for someone else to read and understand it better. But having too many of them makes it difficult to manage.

Also does having too many variables hamper my performance?

P.S: please don't answer w.r.t the code in example it was just to convey what I really mean.

1
  • Of course you reuse the same variable...because you've defined it in a function. That's what functions are for.
    – zzzzBov
    Jun 11, 2012 at 18:00

7 Answers 7

26

Having to ask yourself this question is a pretty strong smell that you are not following DRY (Don't Repeat Yourself). Suppose you have this, in a hypothetical curly-brace language:

function doFoo() {
    query = "SELECT a, b, c FROM foobar WHERE baz = 23";
    result = runQuery(query);
    print(result);

    query = "SELECT foo, bar FROM quux WHERE x IS NULL";
    result = runQuery(query);
    print(result);

    query = "SELECT a.foo, b.bar FROM quux a INNER JOIN quuux b ON b.quux_id = a.id ORDER BY date_added LIMIT 10";
    result = runQuery(query);
    print(result);
}

Refactor that into:

function runAndPrint(query) {
    result = runQuery(query);
    print(result);
}

function doFoo() {
    runAndPrint("SELECT a, b, c FROM foobar WHERE baz = 23");
    runAndPrint("SELECT foo, bar FROM quux WHERE x IS NULL");
    runAndPrint("SELECT a.foo, b.bar FROM quux a INNER JOIN quuux b ON b.quux_id = a.id ORDER BY date_added LIMIT 10");
}

Notice how the need for deciding whether or not to use different variables goes away, and how you can now change the logic for running a query and printing the result in one place, rather than having to apply the same modification three times. (For example, you might decide you want to pump the query result through a template system instead of printing it right away).

8
  • 2
    I just love DRY principle :)
    – artjom
    Jun 12, 2012 at 7:38
  • 1
    @tdammers is it good to have just 2 lines of code inside a function?consider if I have this function doFoo() { print (runQuery("Selct a,b,c from XYZ"));}
    – Shirish11
    Jun 12, 2012 at 10:38
  • 1
    No, the call stack does not increase - each call to runAndPrint pushes one stack frame when you call it, and then pops it back when the function exits. If you call it three times, it will do three push/pop pairs, but the stack never grows by more than one frame at a time. You should only really worry about call stack depth with recursive functions.
    – tdammers
    Jun 12, 2012 at 19:55
  • 3
    And functions with just two lines of code are perfectly fine: if two lines make a logical unit, then two lines it is. I have written plenty of one-liner functions, just to keep some bit of information isolated and in one place.
    – tdammers
    Jun 12, 2012 at 19:56
  • 1
    @JamesAnderson: It's a somewhat contrived example, but it serves to illustrate a point. It's not about how many lines of code you have. It's how many times you state the same fact. That's what DRY is about, as well as the Single Source Of Truth principle, the Thou Shalt Not Copy-Paste rule, etc.
    – tdammers
    Jun 13, 2012 at 19:27
14

Normally, this is a bad practice.

Reusing a variable is this way can make code that is confusing to read an understand.

Those reading the code will not expect a variable to be reused in such a way and will not know why a value set at the start has a different value at the end of the function.

The examples you posted are very simple and don't really suffer from this issue, but they are not representative of some code that does reuse variables (where it is set at the start, gets reused somewhere in the middle - out of sight).

The examples you have given lend themselves to encapsulation into functions, where you would pass in the query and execute it.

3
  • what about the system performance does it get affected by it?
    – Shirish11
    Jun 9, 2012 at 11:16
  • @Shirish11 - It might. Depends on the compiler, language, environment and other variables.
    – Oded
    Jun 9, 2012 at 11:31
  • Usually, compiler are good at optimising this. However, it always depend on the compiler/plateform/specific case/configuration.
    – deadalnix
    Jun 9, 2012 at 14:06
7

Self-Documented Code is Easier to Read and Maintain

Follow the Principle of Least Atonishment and of the precept of code-as-documentation: use one variable for one goal, to both make its use easy to understand and the code easy to read without explanations.

Correctly Structured Code is Easier (thus Cheaper) to (Re)Use

Also, here it would appear that query is always used to prepare a statement before executing it. That's probably a sign that you want to refactor part of this code into one (or more) helper methods to prepare and execute the query (to comply to the DRY principle).

This way, you'll effectively:

  • use only one variable in your helper method to identify the query of the current context,
  • need to type less code everytime you want to re-execute a query,
  • render your code more readable for others.

Examples:

Consider this, taken from your example, where the refactored version is obviously better. Of course your snippet was just an example for the purpose of this question, but the concept still holds true and scales.

Your Example 1:

Strings querycre,queryins,queryup,querydel; 
    querycre = 'Create table XYZ ...';
    execute querycre ;
    queryins = 'Insert into XYZ ...';
    execute queryins ;
    queryup  = 'Update  XYZ set ...';
    execute queryup;
    querydel = 'Delete from XYZ ...';
    execute querydel ;

Your Example 2:

 Strings query; 
    query= 'Create table XYZ ...';
    execute query ;
    query= 'Insert into XYZ ...';
    execute query ;
    query= 'Update  XYZ set ...';
    execute query ;
    query= 'Delete from XYZ ...';
    execute query ;

Example 3 (Refactored pseudo-code):

def executeQuery(query, parameters...)
    statement = prepareStatement(query, parameters);
    execute statement;
end

// call point:
executeQuery('Create table XYZ ... ');
executeQuery('Insert into XYZ ...');
executeQuery('Update  XYZ set ...');
executeQuery('Delete from XYZ ...');

The benefit shows with regular reuse.

Personal Anecdote

I originally started as a C programmer working with limited screen real-estate, so re-using variables made sense both for the compiled code (back then) and to allow more code to be readable at once.

However, having then moved on to higher-level languages and brushed up on functional programming, I took the habit of using immutable variables and immutable references whereever possible to limit side-effects.

What's In It For Me?

If you take the habit of having all your function's inputs be immutable and to return a new result (as a true mathematical function would), you get into the habit of not duplicating stores.

By extension, this leads to:

  • you writing short functions,
  • with well-defined objectives,
  • that are easier to understand,
  • to re-use,
  • to extend (whether by OO inheritance or by functional chaining),
  • and document (as already self-documenting).

I'm not saying there's no benefit to mutable state here, I'm just pointing out how the habit might grow on you and how it impacts code readability.

2

In Terms of Code Design

In general, it's alright to reuse variables to store different values - after all, that's why they are called variables, because the value stored in them varies - as long as the value is not only of the same type but also means the same thing. For example of course it's okay to reuse the currentQuery variable here:

for currentQuery in queries:
    execute query;

Naturally there's a loop so you have to reuse a variable, but even if there wasn't a loop it would have been okay. If the value does not mean the same thing, use a separate variable.

Specifically, though, the code you are describing does not look very good - it repeats itself. It's much better to use a loop or helper method calls (or both). Personally I've very rarely seen production code that looks like either your 1st or 2nd versions, but in the cases I have, I think the 2nd version (variable reuse) was more common.

In Terms of Performance

It depends on the language, compiler(s) and runtime system(s) used, but in general there should not be any difference - in particular compilers for stack-based register machines (like the popular x86/x86-64) will anyway just use whatever free stack memory or register they can as the assignment target, completely ignoring whether you wanted the same variable or not.

For instance, gcc -O2 generates the exact same binary, and the only performance difference I know of is the size of the symbol table during compilation - completely negligible unless you go back in time to the 60s.

A Java compiler will generate bytecode which needs more storage for the 1st version, but the JVM's jitter will remove it anyway, so again, I suspect there would be practically no noticeable performance impact even if you need highly-optimized code.

0

I think reusing the variable is fine most of the time.

For me, I simply reuse the query variable most of the time. I almost always execute the query right after. When I don't execute the query right away, I usually use a different variable name.

-1

It can increase stack usage if your compiler is particularly dumb. Personally I don't think having a separate variable for each query adds to any readability whatsoever, you still need to actually look at the query string to see what it does.

1
  • I have just provided with a simple example so that its easier for readers to understand what I seek. My code is much more Complex than this.
    – Shirish11
    Jun 9, 2012 at 11:18
-2

In the example, I'd go with the second example. It's quite clear to both a reader and optimizers what you are doing. The first example is a bit more proper, and with somewhat more complicated code I'd use it, but do it like:

{
    String query = 'Create table XYZ ...';
    execute query;
}
{
    String query = 'Insert table XYZ ...';
    execute query;
}
And so on...

(At this point, I might consider tdammers's solution.)

The problem with the first example is that querycre is in scope for the whole block, which might be extensive. This can confuse someone reading the code. It can also confuse the optimizers, which might leave in an unnecessary memory write so querycre is available later if needed (which it's not). With all the braces, query is stored only in a register, if that.

With phrases like "Create table" and "execute" it doesn't look to me like an extra memory write is going to be noticed here, so I'd only fault the code for confusing the reader. But it's handy to be aware of this if you're writing code where speed does matter.

3
  • I disagree. If you were to prefer the second example for clarity, it should be refactored to successive calls to a helper method. it woud convey more meaning, and require less code.
    – haylem
    Jun 12, 2012 at 7:18
  • @haylem: In a real simple case, like this one, you're adding a helper method, which someone reading the code has to go and find. (And someone might have trouble with the helper method and have to figure out all the places it's called from.) Less clarity, about the same amount of code. In a more complicated case, I'd go with my solution, then with tdammer's. I answered this question mostly to point out the (admittedly obscure, but interesting) problems underused variables pose to both humans and optimizers. Jun 12, 2012 at 13:27
  • @haylem: you and tdammer both give the correct solution. I just think it can be overkill in some cases. Jun 12, 2012 at 13:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.