Another use occurred to me today, so I searched the web excitedly and found an existing mention of it: Defining Variables inside Block Scope.
Background
JavaScript, in spite of its superficial resemblance to C and C++, does not scope variables to the block they are defined in:
var name = "Joe";
if ( true )
{
var name = "Jack";
}
// name now contains "Jack"
Declaring a closure in a loop is a common task where this can lead to errors:
for (var i=0; i<3; ++i)
{
var num = i;
setTimeout(function() { alert(num); }, 10);
}
Because the for loop does not introduce a new scope, the same num
- with a value of 2
- will be shared by all three functions.
A new scope: let
and with
With the introduction of the let
statement in ES6, it becomes easy to introduce a new scope when necessary to avoid these problems:
// variables introduced in this statement
// are scoped to each iteration of the loop
for (let i=0; i<3; ++i)
{
setTimeout(function() { alert(i); }, 10);
}
Or even:
for (var i=0; i<3; ++i)
{
// variables introduced in this statement
// are scoped to the block containing it.
let num = i;
setTimeout(function() { alert(num); }, 10);
}
Until ES6 is universally available, this use remains limited to the newest browsers and developers willing to use transpilers. However, we can easily simulate this behavior using with
:
for (var i=0; i<3; ++i)
{
// object members introduced in this statement
// are scoped to the block following it.
with ({num: i})
{
setTimeout(function() { alert(num); }, 10);
}
}
The loop now works as intended, creating three separate variables with values from 0 to 2. Note that variables declared within the block are not scoped to it, unlike the behavior of blocks in C++ (in C, variables must be declared at the start of a block, so in a way it is similar). This behavior is actually quite similar to a let
block syntax introduced in earlier versions of Mozilla browsers, but not widely adopted elsewhere.
Yes, it was added in version 2.5. The expression syntax is:
a if condition else b
First condition
is evaluated, then exactly one of either a
or b
is evaluated and returned based on the Boolean value of condition
. If condition
evaluates to True
, then a
is evaluated and returned but b
is ignored, or else when b
is evaluated and returned but a
is ignored.
This allows short-circuiting because when condition
is true only a
is evaluated and b
is not evaluated at all, but when condition
is false only b
is evaluated and a
is not evaluated at all.
For example:
>>> 'true' if True else 'false'
'true'
>>> 'true' if False else 'false'
'false'
Note that conditionals are an expression, not a statement. This means you can't use assignment statements or pass
or other statements within a conditional expression:
>>> pass if False else x = 3
File "<stdin>", line 1
pass if False else x = 3
^
SyntaxError: invalid syntax
You can, however, use conditional expressions to assign a variable like so:
x = a if True else b
Think of the conditional expression as switching between two values. It is very useful when you're in a 'one value or another' situation, it but doesn't do much else.
If you need to use statements, you have to use a normal if
statement instead of a conditional expression.
Keep in mind that it's frowned upon by some Pythonistas for several reasons:
- The order of the arguments is different from those of the classic
condition ? a : b
ternary operator from many other languages (such as C, C++, Go, Perl, Ruby, Java, Javascript, etc.), which may lead to bugs when people unfamiliar with Python's "surprising" behaviour use it (they may reverse the argument order).
- Some find it "unwieldy", since it goes contrary to the normal flow of thought (thinking of the condition first and then the effects).
- Stylistic reasons. (Although the 'inline
if
' can be really useful, and make your script more concise, it really does complicate your code)
If you're having trouble remembering the order, then remember that when read aloud, you (almost) say what you mean. For example, x = 4 if b > 8 else 9
is read aloud as x will be 4 if b is greater than 8 otherwise 9
.
Official documentation:
Best Answer
Such an operator isn't part of the current Delphi version because it wasn't part of the previous version, and demand wasn't great enough to justify the cost of adding it. (You'll find that explanation applies to lots of features you wish you had in lots of products.)
Delphi provides a set of
IfThen
functions in the Math and StrUtils units, but they have the unfortunate property of evaluating both their value parameters, so code like this will fail:To really do it right, there needs to be help from the compiler. Within the Delphi community, I sense a general dislike of the C-style syntax using a question mark and a colon. I've seen proposals that would use syntax like this:
Part of what makes conditional operators so attractive is that they let you write concise code, but Delphi's style of writing everything out makes the above unappealing, even if put all on one line.
It doesn't really need to be in the form of an operator. Delphi Prism provides a compiler-magic function
Iif
that only evaluates one of its two value parameters:You asked why a feature like this wouldn't have been added along with all the other language features added in Delphi 2009. I think that's your reason. There were plenty of other language changes going on that already required delicate handling; the developers didn't need to be burdened with even more. Features aren't free.
You asked whether Delphi will ever have such a feature. I'm not privy to Embarcadero's planning meetings, and I had to send my crystal ball away for repairs, so I can't say for certain, but I predict that if it ever would have such a feature, it would come in the form of Delphi Prism's
Iif
function. That idea shows up near the end of the discussion in Quality Central, and an objection is made that, as a new reserved word, it would break backward compatibility with other people's code that already defines a function with the same name. That's not a valid object, though, because it wouldn't need to be a reserved word. It could be an identifier, and just likeWriteln
andExit
, it can be eligible to be redefined in other units even though the one from the System unit is treated specially.