Q:

Initialization and Scope in Swift

The code bellow won't be compiled and the Swift compiler will show an error: "Variable 'firstVar' used before being initialized".
var firstVar: Double
var secondVar = 2.0

if 1 > 0 {
    firstVar = 2.0
}

print(firstVar)

At the same time the Swift compiler (2.2) has no problem with the following code, it prints "Hello, Stack Overflow". For the Swift 3.0, the following code will show an error as expected.
var firstVar: Double
var secondVar = 2.0

if 1 > 0 {
    firstVar = 2.0
}

if secondVar > 1.0 && firstVar > 0 {
    print("Hello, stackoverflow!")
}

Could you explain, why the second condition of the if-statement in the second code example evaluates to true and the compiler (Swift 2.2) doesn't complain about the firstVar being initialized while in the first code example it does.

A:

Delaying the evaluation of an expression by wrapping it in a closure: limitations of the Swift playground's on-the-fly "compilation" lets this erroneous program flow pass without error
The rhs expression of && (= firstVar) is automatically wrapped in a closure (here: using autoclosure), which means the evaluation of firstVar is delayed (lazily), such that your examples will "compile" when using the on-the-fly compilation of the Swift Playground. I can speculate that even preconditions for the correctness of lazy evaluations will be checked only at runtime, and not at compile time, when using the Swift Playground.
When attempting the same in an actual project, the compiler needn't restrain itself to quick on-the-fly compilation, and can spot the compile time error for what it is:

"error: variable '...' captured by a closure before being initialized"

I.e., the above shouldn't compile, but does actually run fine due to the conditional initialization of firstVar in the body of the if statement. Note that the fact that 1 > 0 is true should not affect the fact that this is a compile time error, as evaluating the state of 1 > 0 is a runtime decision.

Details
The logical binary infix operator '&&' has a right had side rhs that is implemented lazily, with @autoclosure
func &&(lhs: BooleanType, @autoclosure rhs: () -> BooleanType) -> Bool {
    return lhs.boolValue ? rhs().boolValue : false
}

From The Language Reference - Attributes:

autoclosure
This attribute is used to delay the evaluation of an expression by
  automatically wrapping that expression in a closure with no arguments.
  Apply this attribute to a parameter declaration for a function or
  method type that takes no arguments and that returns the type of the
  expression. Declarations with the autoclosure attribute imply
  noescape as well, except when passed the optional attribute argument
  escaping.

We can show the behaviour of your example even more clearly by the following example:
var foo: Double

/* use autoclosure to capture the argument in a closure */
func bar(@autoclosure arg: () -> Double) {
    print(arg())
}

/* or let the user explicitly supply the argument in a closure form */
func baz(arg: () -> Double) {
    print(arg())
}

if true {
    foo = 1.0
}

bar(foo)        // 1.0, OK in Playground, error when in a project
baz() { foo }   // 1.0, OK in Playground, error when in a project

