Enum methods
On the menu, each line has its price printed next to it. To find it out, you do not need to go to the till: a look at the menu line itself is enough. The answer lives in the same place as the drink.
In the first lesson, a separate function price(of:) worked out the price, and you passed it the drink. You can also keep code about drinks inside the enum itself. Then a case answers a question about itself:
enum Drink {
case tea, coffee
func price(cups: Int) -> Int {
switch self {
case .tea:
return 2 * cups
case .coffee:
return 3 * cups
}
}
}
let drink = Drink.coffee
print(drink.price(cups: 2)) // 6Let's go through the program:
- The function
price(cups:)is declared inside the enum's braces. Such a function is a method of the enum, likehasSuffixon a string. drink.price(cups: 2)calls the method with a dot on the valuedrink.- Inside the method,
selfis the value the method was called on. Here that isdrink, which is coffee. switch selfpicks the.coffeebranch, and the method returns3 * 2, which is6.
A method and self
A method is declared the same way as an ordinary function, only inside the enum, usually after the list of cases. What to know about a method:
- you call it on a value with a dot:
drink.price(cups: 2)orDrink.tea.price(cups: 3); selfinside the method is that value itself, "this line of the menu";switch selfis the usual body of such a method: each case gets its own branch, anddefaultis not needed.
Computed property
A string has count: you read it with a dot and no parentheses. What you read on a value with a dot and no parentheses is called a property. You can give an enum a property too, only your own code will compute it.
Now let the coffee ticket record the number of cups. The price of the order depends on that number:
enum Order {
case tea
case coffee(cups: Int)
var price: Int {
switch self {
case .tea:
return 2
case .coffee(let cups):
return cups * 3
}
}
}
print(Order.coffee(cups: 2).price) // 6A computed property is a property whose value is not stored anywhere but computed anew on every read. Its declaration has three parts:
var—a computed property is declared only withvar: withletthe code does not compile;price: Int—the property's name and type;- the braces—the code that returns the value with
return.
You read the property without parentheses: .price, not .price(). In the .coffee(let cups) branch, the pattern gets the number of cups out, and for two cups the property gives 6.
A short branch can also be written on one line: case .tea: return 2. It is the same branch, only without the line break.
When do you write a method, and when a property? A property fits when the answer needs nothing but the value itself: the order's price, the cup's size. A method is needed when the answer needs data from outside, like the number of cups in price(cups:).
Here the menu picture is inaccurate. A menu prints the price once, but a computed property stores nothing: price runs its switch on every read.
Common mistake
The method was called on the type itself, not on a value:
print(Drink.price(cups: 2)) // ✗error: instance member 'price' cannot be used on type 'Drink'; did you mean to use a value of this type instead?The program does not compile. Drink is the whole menu, not one drink, and it is unclear whose price to work out: the tea's or the coffee's. The compiler suggests that a value of this type is needed. Call the method on a case, Drink.tea.price(cups: 2), or on a constant: drink.price(cups: 2).
Key points
- An enum's method is declared inside its braces and called on a value with a dot:
drink.price(cups: 2). selfinside a method is the value it was called on, andswitch selfpicks a branch by case.- A computed property stores nothing: its code runs on every read, and you read it without parentheses.