I am learning swift using learnxinyminutes.com
I'm having a hard time understanding a component of on of the examples on the site (below), namely the use of underscore in the let statements instead of variable names.
// Variadic Args
func setup(numbers: Int...) {
let _ = numbers[0]
let _ = numbers.count
}
I understand that swift wants you to use underscore if you never declare the variable, but 1) why would you want to declare variables you never use? And 2) is there a way to get those values out if you used _. And, 3) if so, how?
1) why would you want to declare variables you never use?
Generally you don't! There are some cases though where you might want to, such as the example Danny Buonocore gave. Another example might be this: say you want to check that a variable is non-nil before you do something, though you do not need that variable for the subsequent code. (A guard statement is probably more useful in these situations).
if let _ = titleString {
// Do something that doesn't use titleString, but where it being non-nil means this operation is valid
}
Another example is with Swift functions. Names for a second, third, etc. parameter must be identified whenever calling a function. For example:
func externalizedParameters(first: Int?, second: Int?) {
...
}
Which is called using externalizedParameters(5, second: 6).
But if you are doing something trivial, and the function name already makes it clear what the two parameters are, such as with a swap operation, you might not want to force the caller to explicitly state the name of the second parameter. In that case, you can use '_' because you don't care about the name of that externalized parameter:
func swap(first: Int?, _ second: Int?) {
...
}
This can then be called as swap(5, 6) as opposed to swap(5, second: 6).
2) is there a way to get those values out if you used _. & 3) if so, how?
No. You need to name the variable if you want to use the value.
One example would be a loop where you don't necessarily need the index.
for _ in 0..<10 {
}
In swift you can also externalize the names of the parameters. This allows the caller to pass by name, rather than order:
func myFunction(param1:String, param2:String) {
}
myFunction(param2: "second value", param1: "first value");
If you don't want to externalize the name of a parameter, you can include an underscore before it, like so:
func myFunction(param1:String, _ param2:String) {
}
In this case, you must pass the value to set param2 to as the second argument, and you cannot use the naming scheme seen in the first example.
If you need to use the value inside of a variable, declare it with a name and not _. The underscore says, I know this call returns a value but we're not going to use it, so it doesn't need a name. Swift emits warnings for unused function call results, so this is a way to suppress that warning.
Related
In a function, if I'm being passed an int (which is immutable type, i.e let n), how come if I pass this into a function, I can create a var variable of this? Just wondering why swift works this way, and the reason for it .
func checkNum(_ n: Int) -> Bool {
var n = n
}
In this, it let's me do this.
This is called "shadowing" and is allowed in a variety of places because it's convenient for the programmer because it avoids having two similarly named variables in scope. Without this feature, this code would be:
func checkNum(_ n: Int) -> Bool {
var writableN = n
...
}
This raises the possibility of modifying writableN, and then using n again later in the function unintentionally. It also can make the function a bit harder to understand because of the extra variable. (Of course shadowing can also make code more difficult to understand as well, if it's used without care.)
This is very similar to the if let shadowing, such as:
var x: Int? = ...
if let x = x { ... }
This allows you to use x inside the if let as a non-Optional rather than having to come up with some other name for it.
This is a fairly general feature. Whenever there is a new scope, variables can shadow. For example, you can declare variables inside a function that have the same name as properties or globals. You can create scopes inside a function as well
func checkNum(_ n: Int) -> Bool {
var n = n // Shadows previous `let`
do {
let n = 4 // Shadows previous `var`
print(n)
}
return true
}
Used with care, this is helpful. Used too often (as this last example definitely does), it can make the code very confusing.
Your specific case touches on another important aspect of Swift, which is that it tries to control shared mutable state. The n that the function receives is a copy of the integer that was passed. Modifying n would never directly modify the caller's variable. (There's inout to allow this, but it's subtle. It does't share state. It copies the value in, and on return, copies the value back out.)
Since n isn't shared with the caller, Swift makes this very explicit by making it immutable. If you want to modify it, you need to explicitly make another copy, and var n = n does that.
'var' as a parameter attribute has been deprecated in Swift 3 so that is no longer possible. You can get a similar behaviour by using an inout parameter
func checkNum(_ n: inout Int) -> Bool {
n + 1
}
Remember to call the function by passing the parameter like this: checkNum(&n)
In Swift 2, it appears that the first parameter name is not always required when calling a function. Now in Swift 3, the first parameter name is required when calling the function. For example:
func frobnicate(runcible: String) {
print("Frobnicate: \(runcible)")
}
Swift 2.2 allowed the function to be called by simply typing:
Frobnicate("Station")
Swift 3 seems to be requiring that we use the first parameter names of methods such as:
Frobnicate(runcible:"Station")
Is this the case with Swift 3 for all functions and methods or just certain situations?
Yes, this is right. Swift is fixing a language inconsistency this way (this was always required for initializers).
If you don't want to use the external parameter name, just remove it explicitly:
func frobnicate(_ runcible: String) {
print("Frobnicate: \(runcible)")
}
You can read the full rationale in Swift Evolution 0046
You can read The Swift Programming Language (Swift 3) in i-Book. Also you can check this out in WWDC 2016: What's New in Swift
In Swift 3, by default, functions use their parameter names as labels for their arguments. Write a custom argument label before the parameter name, or write _ to use no argument label.
fun greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
or
// This also works with Swift 2
fun addThreeNumber(_ first: Int, _ second: Int, _ third: Int) {
print(first+second+third)
}
addThreeNumber(1, 2, 3)
Exactly. In Swift 3.0, it's mandatory to write parameter names for all the parameters (including the first parameter). Parameter name is the one which is used inside the function implementation body.
func frobnicate(runcible: String) {
print("Frobnicate: \(runcible)")
}
By default, the external parameter label is same as the parameter name, if you don't specify any parameter label explicitly. Parameter label is the one which is used to pass the arguments while calling the function. If you need, for better clarity purpose, you can also specify external parameter labels explicitly. Example below-
func frobnicate(runcibleExternalLabel runcible: String) {
print("Frobnicate: \(runcible)")
}
If you want to skip the external parameter label while calling the function, just prepend a "_" before the parameter name.
func frobnicate(_ runcible: String) {
print("Frobnicate: \(runcible)")
}
Yes Swift 3 requires you to send First Parameter Label.
Please refer Swift 3 changes
The reason you want labels for parameters is so other code can supply parameters in any order.
Without labels, when you call the function the parameters are anonymous and you cannot be certain if you have supplied them in the wrong order.
Place labels in front of the parameters and code tools can do a much better job at catching errors us humans put in.
The underscore is just a way to cope with the transition from legacy code; method names including an Implicit first parameter. You should change any underscores that migration adds to your code to an explicit parameter label. You know it makes sense.
Looking at this example of conditionals I am confused.
Here is the code and my interpretation
var animal = Animal(name: "Lenny", species: "lemur", tailLength: 12)
animal = Animal(name: "Gilbert", species: "Gorilla", tailLength: nil )
if let tailLength = animal.tail?.length {
print("\(animal.name)'s tail is \(tailLength) long")
} else {
print("\(animal.name) doesn't have a tail.")
}
We have a variable "Animal". Not all animals have tails and so some tailLength values will return nil.
To me, an optional is something with options - in this case it can be an Int or nil (In the case of Gilbert above).
Now, when we want to unwrap it, we are using chaining to check if it will return nil. If it returns an Int, we return it. If it returns nil, we move to the else statement.
Why is the syntax -
if let tailLength = animal.tail?.length
rather than
if let tailLength = animal.taillength?
or
if let tailLength = animal.tail.length?
Note: New to programming. I'm aware that perhaps the answer requires some prerequisite knowledge of other languages and common syntax.
Let's clear this up.
First some prerequisites…
Optionals
Optionals do not necessarily imply options. Instead, "optional" simply implies that the value may or may not exist, hence it is "optional". Think of Optionals as containers sized just right so that they may only hold one specific type. For example, an Optional created specifically to hold an Int could never hold a String, and vice versa. By this definition, Optionals sound exactly the same as variables and constants, but the big difference to note is that unlike regular variables and constants, the containers for Optionals may contain "no value at all", AKA nil or they may contain a value of their specified type. There are no other options.
Optionals are used anytime it makes sense for there to be no value at all, since nil is a better representation of "nothing" than say, -1 for an Integer.
For example,
class Contact {
var name: String
var phoneNumber: String?
var emailAddress: String?
init(name: String, number: String?, emailAddress: String?) {
self.name = name
self.phoneNumber = number
self.emailAddress = emailAddress
}
}
This is a vastly simplified version of what you might use to represent an entry in a contacts app. For simplicity, we'll use Strings to represent each of these properties. The question mark after the type name means that we do not want these properties to be of type String, but instead String?, or "Optional String". The app requires the user to enter their name, but the user may or may not choose to provide a phone number or email address, so the corresponding properties are declared as optional Strings. If the user provides an email address, for example, then the emailAddress property will hold a String representing the address. If the user had not provided an address, the emailAddress property would not hold a String but instead nil, or the absence of a value.
Behind the scenes, an Optional is just an enumeration with two cases: None, and Some with a wrapped value of the type the optional was declared. If you're not familiar with Swift enumerations or this is confusing to you, please ignore this paragraph. It is not important in order to understand Optionals.
Optionals always have only two options. Either nil or a value of the type they were declared.
Unwrapping Optionals
Now suppose we want to access an Optional at some point. We can't just reference it because there is a possibility that it could be nil and our calculation wouldn't function properly. For example, if we wanted to access the user's email address, we might try something like
let user = Contact(name: "Matt", number: nil, emailAddress: nil)
sendEmail(user.emailAddress)
Assuming that the sendEmail function requires a String representing the address as an argument, Swift will report an error and not let the code compile as is. The problem is that we cannot guarantee that there will actually be a String to pass sendEmail. sendEmail requires a String but we are trying to pass it a String?. These are not the same type. If we know that the value will indeed exist, we can just append an exclamation mark immediately after the value that is optional. So, continuing with our example,
let user = Contact(name: "Matt", number: nil, emailAddress: nil)
sendEmail(user.emailAddress!)
Here, the exclamation mark tells Swift that we are sure there will be a value in the emailAddress property, so Swift goes ahead and converts the String? to a String with the value. If at runtime it turns out that emailAddress evaluates to nil, we will get a fatal error. Of course, in this case, we will get a fatal error at runtime because emailAddress did indeed contain nil.
Much of the time, however, and especially in our Contact example, we will not be able to guarantee that a emailAddress exists. Now introducing Optional Binding…
Optional Binding
For times when we simply do not know whether a value exists, but would like to use that value for something if it does, we can use Optional Binding.
Suppose we want to send the user an email if they provided their address. Well, we would need to ensure the value is not nil, assign it to a constant if it isn't, and do some workaround if it is. Here's a perfectly valid way of doing so:
if user.emailAddress != nil {
let address = user.emailAddress!
sendEmail(address)
} else {
promptForEmailAddress()
}
Here, we are checking to make sure the address is not nil. If it is, we will ask the user to give it to us. If the address does exist (if it's not nil), we will assign it to a constant by force unwrapping it with an exclamation mark. We can do this because if the if statement resolves to true, we can be absolutely certain that user.emailAddress will not be nil. sendEmail is then satisfied because address is of type String and not String?, since we unwrapped it first.
But because this is such a common pattern in Swift, the language defines a simplified way of doing this (Optional Binding). The following code snippet is exactly equivalent to the snippet above.
if let address = user.emailAddress {
sendEmail(address)
} else {
promptForEmailAddress()
}
With optional binding, you combine the assignment operation with the if statement. If whatever is on the right of the equals operator (assignment operator) evaluates to nil, the else clause is called and the address constant is never created. If, however, the expression on the right of the equals operator does indeed contain a value, in this case a String, then the address constant is created and initialized with whatever String value was stored in emailAddress. The type of address is therefore String and not String? because if the constant is created, we know it is not nil.
Optional Chaining
Now, sometimes you need to access properties that are at the end of a long chain of objects. For example, suppose emailAddress was not a String but instead a special Email object that held several properties of its own, including a domainName declared as a 'String'.
visitWebAddress(user.emailAddress.domainName)
If one of these values (user, emailAddress, or domainName) was declared as an Optional, this would not be a safe call and Swift would yell at us because our imaginary visitWebAddress function expects a String, but got a String?. Actually, this is not even valid code because we should have a ? after emailAddress. What's going on here? Well, remember that emailAddress was declared as a String?, or "optional string". Anytime we want to access a property using dot syntax on an already optional value, we must use either an exclamation mark (which forces the Optional unwrapped and returns the value which must exist) or a question mark. Whether we choose ! or ?, the symbol must immediately follow the property that was declared to be Optional.
visitWebAddress(user.emailAddress?.domainName)
This statement is syntactically correct. The question mark tells Swift that we realize emailAddress could be nil. If it is, the value of the entire statement user.emailAddress?.domainName will be nil. Regardless of whether emailAddress actually is nil or not, the resulting type of user.emailAddress?.domainName will be String?, not String. Therefore, Swift will still yell at us because visitWebAddress expected a String, but got a String?.
Therefore, we could use a combination of Optional Binding and Optional Chaining to create a simple and elegant solution to this problem:
if let domain = user.emailAddress?.domainName {
visitWebAddress(domain)
}
Remember, the expression on the right side of the equal operator is evaluated first. As already discussed, user.emailAddress?.domainName will evaluate to a String? that will be nil if the email address was not specified. If this is the case and the expression evaluates to nil, no constant is ever created and we are done with the if statement. Otherwise, the value is bound (hence "Optional Binding") to a created constant domain (which will have type String) and we can use it inside the if clause.
As a side note, Optional Chaining can sometimes result in no action at all taking place when a value is nil. For example,
textField?.text = "Hello"
Here, if textField evaluates to nil (for example if the UI has not loaded yet), the entire line is skipped and no action is taken.
Now for your exact question,
Code Analysis
Based on your posted code sample, this is what is likely going on. The Animal class probably looks something like this at a minimum:
class Animal {
let name: String
let species: String
let tail: Tail?
init(name: String, species: String, tailLength: Int?) {
self.name = name
self.species = species
if let lengthOfTail = tailLength {
self.tail = Tail(length: lengthOfTail)
}
}
}
Now, you're probably wondering what is up with all this mention of a Tail object, so this is probably also existent somewhere behind the scenes, looking like this at a minimum:
class Tail {
let length: Int
init(length: Int) {
self.length = length
}
}
(Now going back and looking at Animal should make more sense.)
Here, we have a Tail object with one property called length, of type Int (not optional). The Animal class, however, contains a property called 'tail' which is of type Tail?, or "optional Tail". This means that an Animal may or may not have a tail, but if it does it is guaranteed to have a length of type Int.
So here…
if let tailLength = animal.tail?.length {
print("\(animal.name)'s tail is \(tailLength) long")
} else {
print("\(animal.name) doesn't have a tail.")
}
…a ? immediately follows tail because it is the property that is optional. The statement animal.tail?.length has a type of Int? and if it is nil because tail is nil, the else clause is called. Otherwise, a constant tailLength is created and the tail length as an Int is bound to it.
Note that in the Animal initializer, it simply took an Int? for tailLength, but behind the scenes it checked to see if it was nil and only if it wasn't did it create a Tail object with the specified length. Otherwise, the tail property on the Animal was left nil, since nil is the default value of a non-initialized optional variable or constant.
Hope that clears up all of your questions on Optionals in Swift. The Swift Language Guide has some great content on this, so check it out if needed.
I am trying to understand how parameters passed to a method are available to nested closures. I'm nervous that something I wrote won't always have the original parameters available.
(these are drastically simplified examples)
I have a method that I wrote that specifies a closure as a parameter:
func saveNameAndAgeToServer(serverParams: [String:String], completionHandler: (age: NSNumber) -> ()) {
// Connect to a server
// POST a name and dob from serverParams
// Receives a current age in completion:
completionHandler(age: 22)
}
Now somewhere else I create another method, that also specifies a closure, takes two parameters and calls the first function:
func AwesomeFunc(name: String, dob: NSDate, completionHandler: (isOverTwentyOne: Bool) -> ()) {
let formattedDob = NSDateFormatter().stringFromDate(dob)
saveNameAndAgeToServer([name:formattedDob]) { (age) -> () in
if (age as Int) >= 21 {
print("\(name) can have a beer.")
completionHandler(isOverTwentyOne: true)
} else {
print("\(name) is too young to drink, he can have a water.")
completionHandler(isOverTwentyOne: false)
}
}
}
Am I able to guarantee that the parameters (name and dob) passed into this latter function will always be available?
What I'm trying to ask is will the memory that the saveNameAndAgeToServer closure runs within always have the parameters of AwesomeFunc available to it? I'm pretty sure the function is all being held while whatever it calls is completed but would love a 2nd opinion.
You are correct, captured variables will last for the life of the closure. Here's an exert on capturing variables from apple's swift documentation:
A closure can capture constants and variables from the surrounding
context in which it is defined. The closure can then refer to and
modify the values of those constants and variables from within its
body, even if the original scope that defined the constants and
variables no longer exists.
In Swift, the simplest form of a closure that can capture values is a
nested function, written within the body of another function. A nested
function can capture any of its outer function’s arguments and can
also capture any constants and variables defined within the outer
function.
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html
I was surprised by the following playground I created after seeing some unexpected behavior in my code:
import Foundation
let bytes:[UInt8] = [20, 30, 40, 50, 60, 70]
var stream = bytes.generate()
func consumeTwo(var stream:IndexingGenerator<[UInt8]>) {
print(stream.next())
print(stream.next())
}
consumeTwo(stream) // This prints 20 and 30
print(stream.next()) // This prints 20!? I expected 40!
I had thought that marking the stream argument as var to the consumeTwo() function, the stream state/position would be shared/updated as it moved from function to function. But that appears to not be the case.
Does this mean I need to make that an inout? And pass with the ampersand? When does one use the var if that's the case?
More generally... what is the right/idiomatic way to create a stream over a byte array which can be passed from function to function (e.g. a decoder) and preserve the position of the stream as it is passed around?
+1 for archaic English in the question title. :)
When you use var in a function signature, you create a local copy of that value. It's the same as if you did this:
func consumeTwo(stream: IndexingGenerator<[UInt8]>) {
var localStream = stream
print(localStream.next())
print(localStream.next())
}
When the parameter is a reference type (i.e. a class), the duplicate "value" is a duplicate reference to the same object. But the thing you get from Array.generate() is a value type, so your local copy is a separate iterator with separate state.
Does this mean I need to make that an inout? And pass with the ampersand?
Yes — for your simple example, inout (and pass with &) is a simple and idiomatic way to do this:
func consumeTwo(inout stream:IndexingGenerator<[UInt8]>) {
print(stream.next())
print(stream.next())
}
consumeTwo(&stream) // This prints 20 and 30
print(stream.next()) // This prints 40
Remember: when you want to modify a value type inside a function and later see those modifications outside the function, use inout. And the & goes with it, so that it's clear both inside the function and at the call site that this behavior is happening.
When does one use the var if that's the case?
Use var for parameters only when you want to make a copy that's local to the function invocation. Admittedly, the use cases for this are few. Here's a contrived (and completely unnecessary) one:
func bananify(var strings: [String]) {
for i in 1.stride(to: strings.count, by: 2) {
strings[i] = "banana"
}
print(strings.joinWithSeparator(" "))
}
let words = ["foo", "bar", "bas", "zap", "asdf"]
bananify(words) // "foo banana bas banana asdf\n"
If you find this confusing, you're not the only one. For this reason, removing the ability to use var for parameters is a planned change for Swift 3.
More generally... what is the right/idiomatic way to create a stream over a byte array which can be passed from function to function (e.g. a decoder) and preserve the position of the stream as it is passed around?
As user3441734 notes, you can indeed create and use a reference-type iterator instead. Or you can write a reference type that holds and manages an iterator. For your hypothetical case of sharing a stream among several subsystems of a program, this is probably a good approach — representing a shared resource is one of the canonical cases for using reference types.
you wrote "It makes me wish that Generators were objects instead of structs."
there is no trouble define some generator as reference type ...
class G: AnyGenerator<Int> {
var i = 0
override func next() -> Int? {
return i++
}
}
let g = G()
func foo(gen: G)->Void {
print(gen.next())
print(gen.next())
}
foo(g)
print(g.next())
/*
Optional(0)
Optional(1)
Optional(2)
*/