3

Java does not support this construct:

if ((int ext_pos = fname.lastIndexOf('.')) >= 0)
    fname = fname.substring(0,ext_pos);

(I get syntax errors when compiling).

However, some other languages support things like that, e.g., in Perl I can write

if (defined (my $foo = $bar{$baz})) { ... do stuff with $bar ... }
# $bar does not exist here

Obviously, this is more of syntactic sugar than anything else, since one can re-write it in Java as

{
    int ext_pos = fname.lastIndexOf('.');
    if (ext_pos >= 0)
        fname = fname.substring(0,ext_pos);
}

at the cost of 3 extra lines of code.

How is this construct called?

(Bonus questions: Which languages support it? Why don't Java & C++ support it?)

sds
  • 58,617
  • 29
  • 161
  • 278
  • 1
    C++ allows _assignments_ inside expressions, but not _variable declarations_. Java doesn't allow either. – DaoWen Jun 27 '13 at 17:10
  • 4
    You definitely can put assignments into expressions in Java. For example in `i = j = k = 0;`. – biziclop Jun 27 '13 at 17:12
  • 1
    Because java is too verbose and Perl is a nice hackity language :-) – Ayman Jun 27 '13 at 17:15
  • @biziclop - You're right—not sure why I thought assignments weren't allowed. It's probably because Java is more strongly typed than C, so you have to coerce the assignment to a boolean to put it in a condition. Thanks for pointing that out! – DaoWen Jun 27 '13 at 17:16
  • 2
    I don't think there's actually a name for this—it's just _allowing declarations in expressions_. I don't think it's common enough to have its own specialized term. – DaoWen Jun 27 '13 at 17:19
  • 3
    Alternatively, if you want to annoy the hell out of everyone reading your code and want to earn yourself an appearance on TheDailyWTF, you can write: `for( int ext_pos = fname.lastIndexOf('.'); ext_pos >= 0; ext_pos = -1 ) fname = fname.substring(0,ext_pos);`, because for() does expect a statement there. – biziclop Jun 27 '13 at 17:21
  • I don't think this construct has a name, if declarations are defined as expressions in a language, you can do it, if they're statements (as in Java), you can't. – biziclop Jun 27 '13 at 17:23
  • I dont understand the question 'How is this construct called?' - If you mean 'What is it called?', Its a contractual check. assert(fname.lastIndexOf('.') >= 0); fname_without_extension = fname.substring(0, fname.lastIndexOf('.')); might be a better way of writing your intentions – Michael Brown Jun 27 '13 at 17:26
  • @DaoWen: I would have accepted your comments as the answer. – sds Jun 27 '13 at 17:27

4 Answers4

5

You have to move the declaration outside of the if-statement condition. Declarations are statements and can't be used as expressions

int ext_pos;
if ((ext_pos = fname.lastIndexOf('.')) >= 0)
    fname = fname.substring(0,ext_pos);

In some languages as you point out (Perl), you can do this. This is because assignment in those languages can also be considered an expression and as such nested in other expressions.

(I'm not sure what this construct is called)

Hunter McMillen
  • 59,865
  • 24
  • 119
  • 170
  • 5
    -1 for being totally irrelevant. He knows you can move it outside in Java. He's wondering what it's called when that's allowed (e.g. in Perl). Read the last few lines of the question. – DaoWen Jun 27 '13 at 17:11
  • @DaoWen My comment about expressions and statements was pretty clear I thought. – Hunter McMillen Jun 27 '13 at 17:13
  • +1 for showing how the construct actually is supported in Java, just not with a declaration inside the `if`. – rgettman Jun 27 '13 at 17:14
  • It's not totally irrelevant, as it shows the part that isn't allowed. It doesn't name it, that's true. – biziclop Jun 27 '13 at 17:14
  • @HunterMcMillen - Removed my -1. – DaoWen Jun 27 '13 at 17:18
  • Unlike what OP says, this construct isn't just syntactic sugar, because declared this way, the scope of `ext_pos` is "the rest of the current code block", whereas in the Perl code, the scope is strictly the `if` statement. This is a fundamental difference between the two, and apart from my horror "solution", there's no way in Java to limit the scope of a variable the way you can in Perl. – biziclop Jun 27 '13 at 17:34
2

Java allows assignments inside expressions, but not variable declarations (thanks for the correction biziclop!). C++ has traditionally had the same restriction, but I found another stackoverflow post describing how declarations are allowed in conditions in the C++03 standard. The syntax is limited, but this is allowed (tested on GCC 4.2.1):

int x = 1;
if (int y = x)
  cout << "y = " << y << endl;

Note that as biziclop pointed out, this has the nice property of restricting the scope of y to that within the conditional. If you try to use y outside the conditional you'll get an error:

int x = 1;
if (int y = x)
  cout << "y = " << y << endl;
cout << y; // error: ‘y’ was not declared in this scope

I don't think there's actually a name for this—it's just allowing declarations in expressions. I don't think it's common enough to have its own specialized term.

As for language support. JavaScript sort of supports this in that it allows assignments in expressions, and that if you reference an undeclared variable in JavaScript it just assumes it's global.

if (x = 1) alert(x) // x is global, assigned 1
alert(x) // since x is global it's still in scope and has value 1

Basically, any language in which a declaration is an expression will allow you to do this. In most functional programming languages (e.g. Haskell, ML, Lisp), basically everything is an expression, so you can declare new variable bindings inside the condition (but they wouldn't be available in the body of the conditional). Here's an example in Clojure:

(println          ; print the result of the conditional
  (if (let [x 1]  ; declare local binding x = 1
        (== x 2)) ; check if x == 2
    "is two"      ; true branch result
    "isn't two")) ; false branch result
Community
  • 1
  • 1
DaoWen
  • 32,589
  • 6
  • 74
  • 101
0

Although Java doesn't like it when you to instantiate a variable inside the if statement, it will let you set one.

int ext_pos;
if ((ext_pos = fname.lastIndexOf('.')) >= 0) {
    fname = fname.substring(0, ext_pos);
}

compiles correctly. I know that this is very similar to your solution, but I just wanted to point it out.

Similarly, Matthew Crumely answered a question about setting a variable inside the if conditional statement using another method here. In short, he notes that this can cause some code confusion for others that look at your code.. It can easily look like a noob mistake of using the wrong "=" or "==" even if it really is intended.

My real guess as to why they did this was to keep the code easily readable.

Community
  • 1
  • 1
mojo
  • 65
  • 1
  • 5
0

This is block notation. See Java specification section 14.2. Per The specification:

A block is executed by executing each of the local variable declaration statements and other statements in order from first to last (left to right). If all of these block statements complete normally, then the block completes normally. If any of these block statements complete abruptly for any reason, then the block completes abruptly for the same reason.

Section 14.3 shows an example with this syntax in it, you can also find this syntax throughout the specification.

Robert H
  • 11,520
  • 18
  • 68
  • 110