Alex headshot

AlBlue’s Blog

Macs, Modularity and More

Swift - functions

2014 Swift Mac

In this episode of the Swift introduction series we’ll be looking at functions in Swift.

Defining functions

Swift is an object oriented language that builds upon Objective-C and C++, but it also blends functions and functional programming techniques. It’s a little bit like Scala, except that Swift will become massively successful.

Swift functions can be created and assigned to variables, as they can in JavaScript. Unlike JavaScript, Swift uses the func keyword to introduce a function.

Defining and calling functions
$ swift
Welcome to Swift! Type :help for assistance.
1> func helloWorld() {
2. println("Hello World")
3. }
4> helloWorld()
Hello World

As with other programming languages, variables defined within the block of a function live for the lifetime of that function:

Variables live for lifetime of a function
5> func helloWorld() {
6. let name = "World"
7. println("Hello \(name)")
8. }
9> helloWorld()
Hello World
10> name
error: use of unresolved identifier 'name'

Swift has positional, named and default arguments. These are specified within the parentheses and are comma separated. Unlike variables (which use type inference to determine what the right type is) function arguments must be typed.

Positional arguments in functions
11> func hello(name:String) {
12. println("Hello, \(name)")
13. }
14> hello("World")
Hello, World

Default arguments can be declared by placing a default value afterwards:

Default arguments
15> func greet(name:String, greeting:String = "Hello") {
16. println("\(greeting), \(name)")
17. }
18> greet("World")
Hello, World
19> greet("World", "Hi")
error: missing argument label 'greeting:' in call

This error occurs because default arguments are implicitly named arguments. A named argument is one that must be called with a name instead of its position. Names are specified with the same label as the function name:

Calling named arguments
20> greet("World", greeting:"Hi")
Hi, World

Named arguments don’t have to have a default value though. They can be declared as named arguments by placing a label in front of the argument. Named arguments are said to have an ‘‘external name’’, which is the name callers must use to supply the function, and an ‘‘internal name’’, which is used in the implementation of the body itself. This allows functions to be refactored without affecting their API:

External named arguments
21> func greet(name:String, greeting salutation:String = "Hi") {
22. println("\(salutation), \(name)")
23. }
24> greet("World", greeting:"Yello")
Yello, World

As a special short-cut, it is possible to declare that an argument be named with the same name as the argument name using the # symbol.

Named arguments
25> func greet(#name:String, #greeting:String) {
26. println("\(greeting), \(name)")
27. }
28> greet(name:"World", greeting:"Hello")

Note that even though the arguments are named, they have an implied order. It is not possible to miss out the arguments or re-order them, as is possible in other languages with named arguments:

Named arguments out-of-order
29> greet(greeting:"Hello", name:"World")
error: argument 'name' must precede argument 'greeting'
greet(greeting:"Hello", name:"World")
~~~~~~~~~~~~~~~~ ^ ~~~~~~~

[Side note: Error reporting in Swift is really great. The ASCII graphics at the bottom highlight the erroneous expression (the bit in the parentheses) and the caret shows where the error was found. This is especially useful in a REPL where there isn’t a defined source file or line numbers.]

Named arguments are a throwback to Objective-C, and to allow Swift to interoperate with Objective-C classes (which we’ll look at in a future post). In a few cases they can make an API clearer, but in a lot of cases they add extra noise where none is really required.

Finally, return types and values. As with other languages, the return keyword is used to return from a function and pass a value back. As with arguments, the return type of the function must be specified (it defaults to no return type if not) except that instead of using the : syntax, it invents a new -> syntax instead. This is one of the several annoyances in the language where consistency goes out of the window because not enough code has been written to find out these edge cases.

Adding two numbers
29> func add(i:Int, j:Int) -> Int {
30. return i+j
31. }
32> add(1,2)
$R0: Int = 3

In next week’s episode, we’ll look at how to create classes in Swift. To subscribe to this series, add the Swift tag feed to your reader.