Why Does a Try/Catch Block Create New Variable Scope

Why does a Try/Catch block create new variable scope?

Why are Objects created within the try/catch block not in scope with the rest of the method?

They are. Variables declared within the try/catch block are not in scope in the containing block, for the same reason that all other variable declarations are local to the scope in which they occur: That's how the specification defines it. :-) (More below, including a reply to your comment.)

Here's an object created within a try/catch which is accessible outside of it:

SomeObject someObject = null;
try
{
someObject = new SomeObject();
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod(); // This is fine -- unless the SomeObject
// constructor threw the exception, in which
// case someObject will be null

Note the difference. Where the variable is declared defines the scope in which it exists, not where the object was created.

But based on the method names and such above, the more useful structure for that would be:

SomeObject someObject = new SomeObject();
try
{
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod();

Re your comment:

I guess I'm confused as to why another scope has even been created for a try/catch block.

In Java, all blocks create scope. The body of an if, the body of an else, of a while, etc. — they all create a new, nested variable scope:

if (foo) {
SomeObject bar = new SomeObject();
}
bar.doSomething(); // <== Compilation error, `bar` is not defined

(In fact, even a block without any control structure creates one.)

And if you think about it, it makes sense: Some blocks are conditional, like the one defining the body of an if or while. In the above if, bar may or may not have been declared (depending on the value of foo), which makes no sense because of course the compiler has no concept of the runtime value of foo. So probably for consistency, the designers of Java went with having all blocks create a new nested scope. (The designer of JavaScript went the other way — there is no block scope at all, yet, though it's being added — and that approach also confuses people.)

Why does the Try-Catch block affect a variable in an enclosing scope?

This appears to be a bug in GCC's implementation of copy elision. The C++ standard says the following:

[class.copy.elision] (emphasis mine)

This elision of copy/move operations, called copy elision, is
permitted in the following circumstances (which may be combined to
eliminate multiple copies):

  • in a throw-expression, when the operand is the name of a non-volatile automatic object (other than a function or catch-clause
    parameter) whose scope does not extend beyond the end of the
    innermost enclosing try-block (if there is one)
    , the copy/move
    operation from the operand to the exception object can be omitted by
    constructing the automatic object directly into the exception object

In the following copy-initialization contexts, a move operation might
be used instead of a copy operation:

  • if the operand of a throw-expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter)
    whose scope does not extend beyond the end of the innermost enclosing try-block (if there is one),

This is a family of optimizations that allows the copy initialization of an exception object to be either avoided or done as efficiently as possible. Now, a common implementation of std::string move construction is to leave the source string empty. This appears to be exactly what happens to your code. The temp in the outer scope is moved from (and left empty).

But that is not the intended behavior. The scope of the temp you throw exceeds (by far) the try block it's thrown in. So GCC has no business applying copy elision to it.

A possible workaround is to place the declaration of temp inside the while loop. This initialized a new std::string object every iteration, so even if GCC moves from it, it won't be noticeable.

Another workaround was mentioned in the comments and is to make the outer temp a const object. This will force a copy (since a move operation requires a non-const source object).

Why aren't variables declared in try in scope in catch or finally?

Two things:

  1. Generally, Java has just 2 levels of scope: global and function. But, try/catch is an exception (no pun intended). When an exception is thrown and the exception object gets a variable assigned to it, that object variable is only available within the "catch" section and is destroyed as soon as the catch completes.

  2. (and more importantly). You can't know where in the try block the exception was thrown. It may have been before your variable was declared. Therefore it is impossible to say what variables will be available for the catch/finally clause. Consider the following case, where scoping is as you suggested:


    try
    {
    throw new ArgumentException("some operation that throws an exception");
    string s = "blah";
    }
    catch (e as ArgumentException)
    {
    Console.Out.WriteLine(s);
    }

This clearly is a problem - when you reach the exception handler, s will not have been declared. Given that catches are meant to handle exceptional circumstances and finallys must execute, being safe and declaring this a problem at compile time is far better than at runtime.

PHP variable scope within Try/Catch block

Your code is valid. Variable scope in PHP is by function, not block. So you can assign a variable inside the try block, and access it outside, so long as they're in the same function.

Why is a defined variable in try/catch block showing undefined in the same function scope?

You're right that var is function scoped and not block scoped, however there's an exception for catch blocks if the var declaration has the same name as a catch block bound variable such that the shadowed var declaration will not be lifted to the function scope.

Relevant piece of the spec:
https://262.ecma-international.org/10.0/#prod-annexB-CatchParameter

The Block of a Catch clause may contain var declarations that bind a name that is also bound by the CatchParameter. At runtime, such bindings are instantiated in the VariableDeclarationEnvironment. They do not shadow the same-named bindings introduced by the CatchParameter and hence the Initializer for such var declarations will assign to the corresponding catch parameter rather than the var binding.

Try catch block variable out of scope

isn't declaration without initialization equivalent to initialization
to null?

Local variables need to be initialized by the programmer only, where as instance variables of the class will be initialized by JVM with their default values (based on the type) during object creation.

The other way which gets rid off "out of scope error" is when I put
"return;" at the end of catch blocks.. shouldn't the code just run
fine with out it?

There are two possibilities here:

(1) Green path scenario: If there is no FileNotFoundException in the first try block, then fis variable would have been initialized successfully, so there will not be any error.

(2) Red path scenario: fis will not be initialized upon the FileNotFoundException in the first try block, so if you return from the first catch block itself, then there is no need of fis variable in the last try block (because those lines will never be executed because you are returning from the middle), so there is no initialization error.

When i take the declarations out of the method and make them static it
also works.. do you know what is the reason for this distinction?

static variables will be initialized with default values (like instance variables) by the JVM, so there will not be any variable initialization errors if you mark them as static (JVM already did initialize them).

JavaScript scope in a try block

Javascript has function scope. That means that magicvar will exist from the beginning of the function it's declared in all the way to the end of that function, even if that statement doesn't ever execute. This is called variable hoisting. The same thing happens with functions declarations, which in turn is called function hoisting.

If the variable is declared in global scope, it will be visible to everything. This is part of the reason why global variables are considered evil in Javascript.

Your example will pass undefined into magicFunction if something is false, because magicVar hasn't been assigned to anything.

While this is technically valid Javascript, it's generally considered bad style and will not pass style checkers like jsLint. Extremely unintuitive Javascript like this will execute without any error

alert(a); //alerts "undefined"
var a;

POP QUIZ: What does the following code do?

(function() {
x = 2;
var x;
alert(x);
})();
alert(x);

Why can't I access variables inside a try/catch block?

You have to bring them outside, because otherwise the variable exists only within the try block. But this is an improvement. If you change your code to this:

Reader reader = new FileReader("/my/file/location");
try {
//Read the file and do stuff
} catch(IOException e) {
e.printStackTrace();
} finally {
reader.close();
}

then the code in the try-block, including the finally, can all rely on the reader having been created successfully. Otherwise, in your example, if the instantiation fails your code still tries to close the reader, which will still be null, on the way out.

In this changed example the exception thrown by the instantiation of the reader doesn't get handled by the catch block.

A combination of problems led you here, one is you're more worried about trying to squash all the exceptions with one catch block than you are about making sure the reader is in a valid state before you start calling methods on it. (You'll see this one-try-block-to-rule-them-all style a lot in JDBC code where people just can't bear to write all the nested try blocks, it's too ugly to tolerate.) Also, it's very toy-example-ish to catch all the exceptions locally like this, in real life if something goes wrong you want to let the exception be thrown so the rest of the application can know something went wrong, giving you something like

public void doStuffWithFile() throws IOException {
Reader reader = new FileReader("/my/file/location");
try {
//Read the file and do stuff
} finally {
try {
reader.close();
} catch (IOException e) {
// handle the exception so it doesn't mask
// anything thrown within the try-block
log.warn("file close failed", e);
}
}
}

which is very similar to what try-with-resources does. try-with-resources creates the objects first, then executes the try block, then closes the things it created, making sure that any exception thrown on close does not mask an exception thrown in the try-block. Creating the objects still has the potential to throw an exception, it doesn't get handled by the try-with-resources.

public void doStuffWithFile() throws IOException {
try (Reader reader = new FileReader("/my/file/location")) {
//Read the file and do stuff
}
}

Variable Scope in try-catch block php

If \Proactivve\User\Sessions() is throwing an exception, then none of the other code in the try block is executed. Nothing will be assigned to $_session, and the following line is going to be skipped entirely.

Scoping is not your problem, the problem is that the variables are never created. If you need specific values in the catch block, you need to create them in a context where they cannot be interrupted by an exception.

variable scope inside try catch block

Declare your variables before the try:

StreamReader myReader = null;

etc. Then set them in the try block.



Related Topics



Leave a reply



Submit