41

Introduction

Many "C-like" programming languages use compound statements (code blocks specified with "{" and "}") to define a variables scope.

Here is a simple example.

for (int i = 0; i < 100; ++i) {
    int value = function(i); // Here 'value' is local to this block
    printf("function(%d) == %d\n", i, value);
}

This is good because it limits the scope of the value to where it is used. It is hard for programmers to use value in ways that they are not meant to because they can only access it from within its scope.

I am almost all of you are aware of this and agree that it is good practice to declare variables in the block they are used to limit their scope.

But even though it is an established convention to declare variables in their smallest possible scope it is not very common to use an naked compound statement (that is an compound statement that is not connected to an if, for, while statement).

Swapping the values of two variables

Programmers often write the code like this:

int x = ???
int y = ???

// Swap `x` and `y`
int tmp = x;
x = y;
y = tmp;

Would it not be better to write the code like this:

int x = ???
int y = ???

// Swap `x` and `y`
{
    int tmp = x;
    x = y;
    y = tmp;
}

It looks quite ugly but I think that this is a good way to enforce variable locality and make the code safer to use.

This does not only apply to temporaries

I often see similar patterns where a variable is used once in a function

Object function(ParameterType arg) {
    Object obj = new Object(obj);
    File file = File.open("output.txt", "w+");
    file.write(obj.toString());

    // `obj` is used more here but `file` is never used again.
    ...
}

Why don't we write it like this?

RET_TYPE function(PARAM_TYPE arg) {
    Object obj = new Object(obj);
    {
       File file = File.open("output.txt", "w+");
       file.write(obj.toString());
    }

    // `obj` is used more here but `file` is never used again.
    ...
}

Summary of question

It is hard to come up with good examples. I am sure that there are betters ways to write the code in my examples but that is not what this question is about.

My question is why we do not use "naked" compound statements more to limit the scope of variables.

What do you think about using a compound statement like this

{
    int tmp = x;
    x = y;
    y = z;
}

to limit the scope of tmp?

Is it good practice? Is it bad practice? Explain your thoughts.

10
  • 8
    Why would you do this over creating a named function? IE in your swap example: x and y would be declared outside, then passed into a function called swap, and in swap would be a variable called temp. Commented Nov 10, 2015 at 14:44
  • 1
    @DavidGrinberg I thought right away of std::swap(). Commented Nov 10, 2015 at 16:08
  • 5
    I think it is unnecessarily verbose in short functions (that have small scopes anyway), and if you want to use it to structure large functions, well, it might be acceptable but the actual problem is the large function itself.
    – Bergi
    Commented Nov 10, 2015 at 16:09
  • 2
    Actually, I do use this technique, on a fairly routine basis, for precisely the reasons you state. Commented Nov 10, 2015 at 16:09
  • 1
    In .NET you also have using blocks. In the file example you should used using or some other format to close / dispose the file. In .NET any object that implements dispose I typically put in a using block.
    – paparazzo
    Commented Nov 10, 2015 at 16:12

9 Answers 9

1

The following java code shows what I believe to be one of the best examples of how naked blocks can be useful.

As you can see, the compareTo() method has three comparisons to make, and the results of the first two need to be temporarily stored in a local. The local is just a 'difference' in both cases, but re-using the same local variable is a bad idea, and as a matter of fact on a decent IDE you can configure local variable reuse to cause a warning.

class MemberPosition implements Comparable<MemberPosition>
{
    final int derivationDepth;
    final int lineNumber;
    final int columnNumber;

    MemberPosition( int derivationDepth, int lineNumber, int columnNumber )
    {
        this.derivationDepth = derivationDepth;
        this.lineNumber = lineNumber;
        this.columnNumber = columnNumber;
    }

    @Override
    public int compareTo( MemberPosition o )
    {
        /* first, compare by derivation depth, so that all ancestor methods will be executed before all descendant methods. */
        {
            int d = Integer.compare( derivationDepth, o.derivationDepth );
            if( d != 0 )
                return d;
        }

        /* then, compare by line number, so that methods will be executed in the order in which they appear in the source file. */
        {
            int d = Integer.compare( lineNumber, o.lineNumber );
            if( d != 0 )
                return d;
        }

        /* finally, compare by column number.  You know, just in case you have multiple test methods on the same line.  Whatever. */
        return Integer.compare( columnNumber, o.columnNumber );
    }
}

Note how in this particular case you cannot offload the work to a separate function, as Kilian Foth's answer suggests. So, in cases like this, naked blocks are always my preference. But even in cases where you can in fact move the code to a separate function, I prefer a) keeping things in one place as to minimize the scrolling necessary in order to make sense of a piece of code, and b) not bloating my code with lots of functions. Definitely a good practice.

(Side note: one of the reasons why egyptian curly bracket style truly sucks is that it does not work with naked blocks.)

(Another side note that I remembered now, a month later: the code above is in Java, but I actually picked up the habit from my days of C++, where the closing curly bracket causes destructors to be invoked. This is the RAII bit that rachet freak also mentions in his answer, and it is not just a good thing, it is pretty much indispensable.)

8
  • IMHO using naked block like this is ok. But if I had to write this function by myself, I would prefer to use two different result variables d1 and d2, or dd and dl, that would satisfy any IDEs warning, too, and avoid that naked block either. In my eyes, less braces and less indentation give better readability.
    – Doc Brown
    Commented Nov 12, 2015 at 13:32
  • Unnecessary inline blocks? Using Integer.compare to check for inequality? One letter variable-names? Verbose comments? This code is terrible. Commented Nov 13, 2015 at 21:09
  • @BlueRaja-DannyPflughoeft 1. Integer.compare() is not used to check for inequality here, it is used for relative comparison. And it is the right way to do it. 2. You can either complain about one-letter local variable names or about verbose comments, not both. Pick one. 3. Your opinion about my code being terrible is irrelevant to the question of whether this is a "useful answer", which is what the votes are meant to stand for.
    – Mike Nakis
    Commented Nov 13, 2015 at 23:12
  • What do you mean "egyptian curly bracket style... does not work with naked blocks"? It lets you easily see the difference between a naked block and a controlled block, which is an advantage.
    – Ben Voigt
    Commented Jun 4, 2016 at 23:42
  • @BenVoigt The egyptian curly bracket style requires the opening curly bracket to be placed at the end of the line of the controlling statement. Naked blocks have no controlling statement. Therefore, the two are incompatible. If you have something else in mind, I'd be curious to see an example.
    – Mike Nakis
    Commented Jun 5, 2016 at 0:55
72

It is indeed a good practice to keep your variable's scope small. However, introducing anonymous blocks into large methods only solves half the problem: the scope of the variables shrinks, but the method (slightly) grows!

The solution is obvious: what you wanted to do in an anonymous block, you should be doing in a method. The method gets its own block and its own scope automatically, and with a meaningful name you get better documentation out of it, too.

16
  • 7
    This might provoke method bloat however. I prefer large methods over large classes.
    – Bergi
    Commented Nov 10, 2015 at 16:11
  • 12
    @Bergi, you shouldn't have either. Lots of small classes, each with a single responsibility achieved via a small number of small methods is the winning combination.
    – David Arno
    Commented Nov 10, 2015 at 16:19
  • 7
    @DavidArno: Of course that's the goal, but it might not be (easily) possible. In such cases I prefer long methods over bloated classes.
    – Bergi
    Commented Nov 10, 2015 at 16:22
  • 7
    You shouldn't move your code into methods but functions instead if possible. Don't use C++ as if it were Java.
    – Joe
    Commented Nov 10, 2015 at 16:24
  • 11
    Honestly, but this term "method bloat" is IMHO a myth invented by people who are looking for excuses for not refactoring too big methods into smaller ones.
    – Doc Brown
    Commented Nov 10, 2015 at 22:18
22

Often if you find places to create such a scope it's an opportunity to extract out a function.

In a language with pass-by-reference you would instead call swap(x,y).

For writing the file that would be advisable to use the block to ensure RAII will close the file and free up the resources as soon as possible.

13

I assume you do not know, yet, of Expression-Oriented languages?

In Expression-Oriented languages, (nearly) everything is an expression. This means, for example, that a block can be an expression as in Rust:

// A typical function displaying x^3 + x^2 + x
fn typical_print_x3_x2_x(x: i32) {
    let y = x * x * x + x * x + x;
    println!("{}", y);
}

you may be worried that the compiler will redundantly compute x * x though, and decided to memorize the result:

// A memoizing function displaying x^3 + x^2 + x
fn memoizing_print_x3_x2_x(x: i32) {
    let x2 = x * x;
    let y = x * x2 + x2 + x;
    println!("{}", y);
}

However, now x2 clearly outlives its usefulness. Well, in Rust a block is an expression which returns the value of its last expression (not of its last statement, so avoid a closing ;):

// An expression-oriented function displaying x^3 + x^2 + x
fn expr_print_x3_x2_x(x: i32) {
    let y = {
        let x2 = x * x;
        x * x2 + x2 + x // <- missing semi-colon, this is an expression
    };
    println!("{}", y);
}

Thus I would say that newer languages have recognized the importance of limiting the scope of variables (makes things cleaner), and are increasingly offering facilities to do so.

Even notable C++ experts such as Herb Sutter are recommending anonymous blocks of this kind, "hacking" lambdas to initialize constant variables (because immutable is great):

int32_t const y = [&]{
    int32_t const x2 = x * x;
    return x * x2 + x2 + x;
}(); // do not forget to actually invoke the lambda with ()
2
  • 2
    I came here to mention let expressions, and you beat me to it ;) In my opinion, that's exactly what "naked compound statement" is :) Your C++ example is also very widespread in the Javascript world.
    – Warbo
    Commented Nov 10, 2015 at 16:43
  • @Warbo: I imagine it exists in many languages (as long as they have anonymous functions), I picked C++ both because I am familiar with and because the recommendation came from the chair of the C++ Standard for... some 10 years I think? So that it's hard to be more authoritative. Commented Nov 10, 2015 at 17:25
8

Congratulations, you've got scope isolation of some trivial variables in a large and complex function.

Unfortunately, you've got a large and complex function. The proper thing to do is instead of creating a scope within the function for the variable, to extract it to its own function. This encourages reuse of the code and allows for the enclosing scope to be passed in as parameters to the function and not be pseudo-global variables for that anonymous scope.

This means that everything outside of the scope of the unnamed block is still in scope in the unnamed block. You are effectively programming with globals and unnamed functions run serially without any way to have code reuse.


Furthermore, consider that in many runtimes, all variable declaration within the anonymous scopes is declared and allocated at the top of the method.

Lets look at some C# (https://dotnetfiddle.net/QKtaG4):

using System;

public class Program
{
    public static void Main()
    {
        string h = "hello";
        string w = "world";
        {
            int i = 42;
            Console.WriteLine(i);
        }
        {
            int j = 4;
            Console.WriteLine(j);
        }
        Console.WriteLine(h + w);
    }
}

And when you start digging into the IL for the code (with dotnetfiddle, under 'tidy up' there is also 'View IL'), right there at the top it shows what has been allocated for this method:

.class public auto ansi beforefieldinit Program
    extends [mscorlib]System.Object
{
    .method public hidebysig static void Main() cli managed
    {
      //
      .maxstack 2
      .locals init (string V_0,
          string V_1,
          int32 V_2,
          int32 V_3)

This allocates the space for two strings and two integers at the initialization of the method Main, even though only one int32 is in scope at any given time. You can see a more in depth analysis of this on a tangential topic of initializing variables at Foreach loop and variable initialization.

Lets look at some Java code instead. This should look rather familiar.

public class Main {
    public static void main(String[] args) {
        String h = "hello";
        String w = "world";
        {
            int i = 42;
            System.out.println(i);
        }
        {
            int j = 4;
            System.out.println(j);
        }
        System.out.println(h + w);
    }
}

Compile this with javac, and then invoke javap -v Main.class and you get the Java class file disassembler.

Right there at the top, it tells you how many slots it needs for local variables (output of javap command goes into the explication of the parts of it a bit more):

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=4, args_size=1

It needs four slots. Even though two of these local variables are never in the scope at the same time, it still allocates room for four local variables.

On the other hand, if you give the compiler the option, extracting short methods (such as a 'swap') will do a better job of inlining the method and making more optimal use of variables.

13
  • That analysis only considers different types in different blocks but doesn't test your variant. Commented Nov 10, 2015 at 14:59
  • 4
    "This allocates the space for three integers at the initialization of the function foo" Couldn't a compiler that accounts for variable liveness, observing that qux and baz are never in scope at the same time, just reuse the space? Variable names are just tools to assist the programmer, the compiler doesn't need to preserve them (and in most compiled languages, it doesn't unless you embed symbols for debugging).
    – JAB
    Commented Nov 10, 2015 at 15:02
  • 5
    @JAB that depends on the compiler. In gcc with similar code, both are allocated qux and baz are assigned just a register, and its the same register in each case. With .net IL and Java bytecode, it is likely to allocate the space and then allow JIT to do the escape analysis on it which is much harder to dig into.
    – user40980
    Commented Nov 10, 2015 at 15:05
  • 2
    @Deduplicator In Java, inlining is done by the JIT, not javac. So... it gets tricky again. I am curious though to dig into this and find out what is really going on with the breaking down the bytecode for a class that has this behavior and poking at the JIT internals to turn on debugging to see if I can tease out the "this is what is happening." Though again, this "work" thing during the day can be quite distracting.
    – user40980
    Commented Nov 10, 2015 at 20:47
  • 1
    While I don't think that anything said in the answer or the comments is wrong, I wouldn't let these concerns guide my programming style (at least not at the expense of readability) unless I had evidence that there is a measurable effect in a particular case I care about. Register allocation is a very well studied field and your compiler is likely to do a much better job than you.
    – 5gon12eder
    Commented Nov 10, 2015 at 21:26
3

Yes, naked blocks may limit variable scopes further than you would normally limit them. However:

  1. The only gain is an earlier end of the variables lifetime; you can easily, and entirely unobstrusively limit the beginning of its lifetime by moving the declaration down to the appropriate place. This is common practice, so we are already halfway of where you can get with naked blocks, and this half way comes for free.

  2. Typically, each variable has its own place where it ceases to be useful; just like each variable has its own place where it should be declared. So, if you wanted to limit all variables scopes as much as possible, you would end up with a block for every single variable in many cases.

  3. A naked block introduces additional structure to the function, making its operation harder to grasp. Together with point 2, this can render a function with fully restricted scopes pretty near unreadable.

So, I guess, the bottom line is that naked blocks simply don't pay off in the vast majority of cases. There are cases, where a naked block may make sense because you need to control where a destructor gets called, or because you have several variables with nearly identical end of use. Yet, especially in the later case you should definitely think about factoring the block out into its own function. The situations that are best solved by a naked block are extremely rare.

1
  • Adding (this) additional structure seems to make the method easier to grasp. I could see immediately that the enclosed statements are logically grouped together, helping to understand the flow of processing. In most modern editors I could also navigate to the start or the end of the block or collapse it, making the remaining code easier to read.
    – Alchymist
    Commented Nov 11, 2015 at 11:20
3

Yes, naked blocks are very rarely seen, and I think that's because they are very rarely needed.

One place I do use them myself is in switch statements:

case 'a': {
  int x = getAmbientTemperature();
  int y = getBackgroundIllumination();
  setVasculosity(x * y);
  break;
}
case 'b': {
  int x = getUltrification();
  int y = getMendacity();
  setVasculosity(x + y);
  break;
}

I tend to do this whenever I'm declaring variables within the branches of a switch, because it keeps the variables out of scope of subsequent branches.

1
  • 1
    Interesting example which I think highlights one of the risks of using this approach. The break statements do not depend on anything in the block. They are linked with the case statements, however. As such they should be outside of the block. With that modification though, I like this example.
    – Alchymist
    Commented Nov 11, 2015 at 11:01
3

Good practice. Period. Full stop. You make it explicit to future readers that the variable is not used anywhere else, enforced by the rules of the language.

This is provisional politeness for the future maintainers, because you tell them something you know. These facts could take dozens of minutes to determine in a sufficiently lengthy or convoluted function.

The seconds you'll spend documenting this powerful fact by adding a pair of braces will pay off minutes for each maintainer who will not have to determine this fact.

The future maintainer can be yourself, years later, (because you're the only one who knows this code) with other things on your mind (because the project has long been over and you've been reassigned ever since), and under pressure. (because we're doing this graciously for the customer, you know, they've been long time partners, you know, and we had to smooth out our commercial relationship with them because the last project we delivered was not that up to expectations, you know, and oh, it is just a small change and it should not take that long for an expert like you, and we've got no budget so don't do "overquality")

You'd hate yourself for not doing it.

9
  • And of course, extract functions from these scopes afterwards. That's hard. You have to find names for them. Commented Nov 10, 2015 at 16:16
  • 3
    A function may also defeat the purpose of the anonymous scope: to indicate that the set of variables are local to one part of the function. Extracting it to a function implies that the function is used in other functions as well - and that has the opposite meaning of what you may have intended. I personally use anonymous scopes wherever I can for I/O operations because I'd like to make it implicit that the I/O operation is being done between opening a filehandle and closing it
    – slebetman
    Commented Nov 10, 2015 at 16:44
  • @Laurent LA RIZZA You're right that naming is one of the Hard Things(TM), but it's not always necessary
    – Warbo
    Commented Nov 10, 2015 at 16:47
  • I've up-voted this answer but I would like it even better without the “The future maintainer […] got a lunch with the CEO” paragraph. That one is a little noisy. ;-)
    – 5gon12eder
    Commented Nov 10, 2015 at 21:31
  • 1
    If I ever want to know were a variable is actually used, I never rely on its scope. I just go to the variable, hit * (vim user...), and my editor shows me all of its occurences. I don't think about this, it's like turning the wheel when driving a car. However, when I see a naked block, it's not clear to me why that extra block is there. Is there a need to call some destructor at a specific time? So, the extra block would just send me looking for other reasons d'etre than just giving a hint where the use of some variable ends. I. e. it would just slow down my reading of the function. Commented Nov 10, 2015 at 21:49
2

Additional blocks/scopes add additional verbiage. While the idea carries some initial appeal, you'll soon run into situations where it becomes unfeasible anyway because you have temporary variables with overlapping scope that cannot be properly reflected by a block structure.

So since you cannot make the block structure consistently reflect variable lifetimes anyway as soon as things get slightly more complex, bending over backwards for the simple cases where it does work seems like an exercise in eventual futility.

For data structures with destructors that lock up significant resources during their lifetime, there is the possibility to call the destructor explicitly. As opposed to using a block structure, this does not mandate a particular order of destruction for variables introduced at different points of time.

Of course blocks have their uses when they are tied with logical units: particularly when using macro programming, the scope of any variable not explicitly named as macro argument intended for output is best restricted to the macro body itself in order not to cause surprises when using a macro several times.

But as lifetime markers for variables in sequential execution, blocks tend to be overkill.

2
  • 2
    No. If you fear adding this kind of verbiage, your function is too long to begin with, and your objects too large. Add explicit blocks for variables without overlapping scopes, then extract methods for these blocks, The overlapping scopes will become a clean high level policy. There are far more nested scopes out there than overlapping scopes. Commented Nov 10, 2015 at 16:13
  • 1
    I fully agree with you except for the explicit destructor call: If you explicitly call a destructor on an automatic variable, that destructor will be called twice. Once when you call it, and once the variable goes out of scope. That's rarely what you want. Of course, you may allocate the object on the heap using new and delete, or use placement-new and an explicit destructor call, but an explicit destructor call alone is almost certainly a bug. Commented Nov 11, 2015 at 6:31

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