Reputation: 553
I'm on the second lecture of Stanford's IOS 9 developer course. The lecturer is trying to build a calculator. I can't figure out two parts. One:
if pending != nil {
accumulator = pending!.binaryFunction(pending!.firstOperand, accumulator)
pending = nil
i understand that pending is an optional. but why is it that i still have to force unwrap it when I nested it in an "IF" statement that checks if it is nil or not?
The second part is:
private struct PendingBinaryOperationInfo {
var binaryFunction: (Double, Double) -> Double
var firstOperand: Double
}
why do the two variables need not have an initialiser? is it just because it is under "structure"?
The whole code is below. The two parts where i don't understand are found at the bottom of the chunk.
thanks a lot!
import Foundation
class CalculatorBrain
{
private var accumulator = 0.0
func setOperand(operand: Double) {
accumulator = operand
}
private var operations: Dictionary<String,Operation> = [
"e" : Operation.Constant(M_E),
"√" : Operation.UnaryOperation(sqrt),
"cos" : Operation.UnaryOperation(cos),
"×" : Operation.BinaryOperation({ $0 * $1 }),
"÷" : Operation.BinaryOperation({ $0 / $1 }),
"+" : Operation.BinaryOperation({ $0 + $1 }),
"−" : Operation.BinaryOperation({ $0 - $1 }),
"=" : Operation.Equals
]
private enum Operation {
case Constant(Double)
case UnaryOperation ((Double) -> Double)
case BinaryOperation ((Double, Double) -> Double)
case Equals
}
func performOperation(symbol: String) {
if let operation = operations[symbol] {
switch operation {
case .Constant(let value):
accumulator = value
case .UnaryOperation(let function):
accumulator = function(accumulator)
case .BinaryOperation(let function):
executePendingBinaryOperation()
pending = PendingBinaryOperationInfo(binaryFunction: function, firstOperand: accumulator)
case .Equals:
executePendingBinaryOperation()
}
}
}
private func executePendingBinaryOperation()
{
if pending != nil {
accumulator = pending!.binaryFunction(pending!.firstOperand, accumulator)
pending = nil
}
}
private var pending: PendingBinaryOperationInfo?
private struct PendingBinaryOperationInfo {
var binaryFunction: (Double, Double) -> Double
var firstOperand: Double
}
var result: Double {
get {
return accumulator
}
}
}
Upvotes: 0
Views: 207
Reputation: 154711
if pending != nil { accumulator = pending!.binaryFunction(pending!.firstOperand, accumulator) pending = nil
why is it that i still have to force unwrap it when I nested it in an "IF" statement that checks if it is nil or not?
Swift is a strongly typed language. In this case, pending
is of type PendingBinaryOperationInfo?
. Just because you checked it to make sure it isn't nil
doesn't change the fact that pending
is of type PendingBinaryOperationInfo?
. You still need to unwrap it to access the PendingBinaryOperationInfo
that is wrapped by the Optional.
The check for nil
merely ensures that you can safely unwrap pending
with !
because you now know it won't crash due to pending
being nil
.
Sometimes, programmers will write this like this:
if let unwrappedPending = pending {
accumulator = unwrappedPending.binaryFunction(unwrappedPending.firstOperand, accumulator)
pending = nil
This uses optional binding to unwrap pending
and assign it to a new variable unwrappedPending
that is of type PendingBinaryOperationInfo
(which is not Optional).
Sometimes, you might also see this:
if let pending = pending {
accumulator = pending.binaryFunction(pending.firstOperand, accumulator)
pending = nil // Oh, but this won't work because pending isn't optional
In this case, a new variable pending
which is of type PendingBinaryOperationInfo
is created which hides the original pending
variable. I personally don't like this form because it confuses the issue with 2 different variables of two different types with the same name. In this case, it wouldn't work anyway, because the author also wants to set pending
to nil
, and you no longer have access to the original optional pending
inside the if
.
The second part is:
private struct PendingBinaryOperationInfo { var binaryFunction: (Double, Double) -> Double var firstOperand: Double }
why do the two variables need not have an initialiser? is it just because it is under "structure"?"
Yes. For structures, Swift automatically generates an initializer for you that initializes all properties. You can see this initializer with Xcode's autocomplete feature by typing:
PendingBinaryOperationInfo(
As soon as you type the (
, the initializer will pop up as the suggested completion. Here it is in a Playground:
Upvotes: 1
Reputation: 401
The variable accumulator isn't an optional and cannot become nil, thats the reason why you have to force unwrap the pending optional and cannot use the optional chaining question mark(?) which might return nil.
The struct PendingBinaryOperationInfo has no default values and therefor has to be initialized.
Upvotes: 0
Reputation: 2819
You're checking for nil
but the object hasn't been unwrapped, what you can do is something like this
if let pending = pending { ... }
The second part of your question, the variables in that struct
are NOT nil
therefore when you initialize PendingBinaryOperationInfo
you have to initialize it with non-null
values, you can get around that by assigning default values in the struct
Upvotes: 0