Just An Application

June 29, 2014

So Swift Then: Tuples

A Swift tuple is a composite value comprised of zero or more values.

An instance of a tuple is written as a parenthesis delimited list of comma separated values, like so

    (1, 2, 3)

The values in a tuple do not have to be of the same type, for example,

    (true, 2, ("three"))

The mutability of a tuple in Swift is determined by whether it has been assigned to a constant or a variable.

1.0 Types

The type of a tuple is a function of the number of values and their types and is written in the same way as a tuple but with type names rather than values.

1.1 Zero Values

The type of an empty tuple is written as an empty tuple, like so

    let t0 : ()  = ()

In Swift the type Void is simply an alias for the type of an empty tuple, so you can also write

    let tv : Void  = ()

1.2 One Value

The type of a single value tuple is simply the type of the value [1], so this

    let t1 : (String)  = ("malin")

can also be written like this

    let t1 : String  = ("malin")

or like this

    let t1 : (String)  = "malin"

or, if you are feeling really adventurous, like this

    let t1 : String  = "malin"

1.3 More Than One Value

The type of a tuple with more than one value is more straight-forward.

For example, the type of the tuple

    (true, 2, ("three"))

is

    (Bool, Int, (String))

2.0 Value Access

2.1 The Index Notation

The values comprising a tuple can be accessed using an index-like notation like this

    let triple  = (1, 2, 3)

    let first   = triple.0

The same notation can be use to modify a mutable tuple, for example

    var mutableTriple = (1, 2, 3)

    mutableTriple.2 = 5

2.1 Pattern Matching

The values comprising a tuple can also be accessed using pattern matching like this

    let triple    = (1, 2, 3)
    let (x, y, z) = triple

which results in x having the value 1, y having the value 2, and z having the value 3.

Values within a tuple can be ignored in a pattern by using an underscore (‘_‘) like so

    let triple    = (1, 2, 3)
    let (_, y, _) = triple

As before, y has the value 2.

Pattern matching can also be used in an assignment statement like this

    let fishes    = ("cod", "dab", "eel")
    var oneFish   = ""
    var twoFish   = ""
    var threeFish = ""

    (oneFish, twoFish, threeFish) = fishes

    (oneFish, _, _) = fishes

3.0 Assignment

Assignment of a tuple results in a copy being made, so

    let fishes        = ("cod", "dab", "eel")
    var mutableFishes = fishes

    mutableFishes.0 = "saithe"

    println(fishes)
    println(mutableFishes)

prints

    (cod, dab, eel)
    (saithe, dab, eel)

4.0 Named Values

The values in a tuple can also be named, like so

    var fishes = (first:"cod", second:"dab", third:"eel")

They can then be accessed by their names

    let first = fishes.first

and if the tuple is mutable also modified

    fishes.first = "saithe"

It is also possible to use the index notation and pattern matching to access the values in a named tuple but this is not necessarily a good idea for reasons that will become apparent.

4.1 Named Values And Tuple Types

It is not entirely clear what the type of a tuple with named values is.

It is apparent that if declared explicitly it must include the names so if you try this

    let namedFishes: (String, String, String) = (first:"cod", second:"dab", third:"eel")

you get a compiler error.

On the other hand this works

    ...
    
    typealias namedFishesType = (first:String, second:String, third:String)
    
    let namedFishes: namedFishesType = ("cod", "dab", "eel")

    ...

as does this

     ...
    
    typealias namedFishesType = (first:String, second:String, third:String)
    
    var namedFishes: namedFishesType = (first:"cod", second:"dab", third:"eel")
    
    ...
    
    var unnamedFishes: (String, String, String) = ("flounder", "gudgeon", "hake")

    namedFishes = unnamedFishes

    ...

and this

    ...
    
    typealias namedFishesType = (first:String, second:String, third:String)
    
    var namedFishes: namedFishesType = (first:"cod", second:"dab", third:"eel")
    
    ...
    
    var unnamedFishes: (String, String, String) = ("flounder", "gudgeon", "hake")
    
    unnamedFishes = namedFishes

so for the purposes of assignment unnamed and named tuple values whose elements are of the same type seem to be interchangeable.

In addition for the purposes of assignment the order of the names in a named tuple value does not seem to be significant, so

    ...
    
    typealias namedFishesType = (first:String, second:String, third:String)
    
    let namedFishes: namedFishesType = (first:"cod", second:"dab", third:"eel")

    println(namedFishes)

    ...

prints

    (cod, dab, eel)

and so does

    ...
    
    typealias namedFishesType = (first:String, second:String, third:String)
    
    let namedFishes: namedFishesType = (third:"eel", second:"dab", first:"cod")
    
    println(namedFishes)

    ...

However, just to make things confusing, the order of the names in a named tuple type does seem to be significant, at least for the purposes of using the index notation and pattern matching, so

    ...
    
    typealias namedFishesType = (first:String, second:String, third:String)
    
    let namedFishes: namedFishesType = (first:"cod", second:"dab", third:"eel")

    println("namedFishes.0 == \(namedFishes.0)")

    let (first, second, third) = namedFishes

    println("\(first) \(second) \(third)")

    ...

prints

    namedFishes.0 == cod
    cod dab eel

but

    ...
    
    typealias reversedFishesType = (third:String, second:String, first:String)
    
    let reversedFishes: reversedFishesType = (first:"cod", second:"dab", third:"eel")

    println("reversedFishes.0 == \(reversedFishes.0)")

    let (first, second, third) = reversedFishes

    println("\(first) \(second) \(third)")

    ...

prints

    reversedFishes.0 == eel
    eel dab cod

which is why you might want to think twice about acessing named values in tuples using the index notation and/or pattern matching.

Finally, as already noted, the types of named values are significant when the names are the same, so you cannot do something like this

    ...
    
    typealias namedFishesType = (first:String, second:String, third:String)
    
    // DOES NOT COMPILE: names match, types do not match
    
    let fishes: namedFishesType = (first:"cod", second:2, third:true)

    ...

as are the names when the types are the same, so you cannot do something like this either

    ...
    
    typealias  namedFishesType = (first:String, second:String, third:String)
    
    // DOES NOT COMPILE: types match, names do not match

    let namedFishes: namedFishesType = (one:"cod", two:"dab", three:"eel")

    ...

Notes

  1. At first glance this seems a trifle odd but there is a possible explanation.

    It may have to do with the function return value type in Swift.

    The clue is the fact that Void is an alias for the type of an empty tuple.


Copyright (c) 2014 By Simon Lewis. All Rights Reserved.

Unauthorized use and/or duplication of this material without express and written permission from this blog’s author and owner Simon Lewis is strictly prohibited.

Excerpts and links may be used, provided that full and clear credit is given to Simon Lewis and justanapplication.wordpress.com with appropriate and specific direction to the original content.

June 28, 2014

So Swift Then: Optionals Or Wot No nil ?

One of the more interesting features of Objective-C is the ability to send messages to non-existent objects, so

    ...
    
    NSString* path      = nil;
    BOOL      isTxtFile = [[path lastPathComponent] hasSuffix:@".txt"];
    
    if (isTxtFile)
    {
        printf("is text file\n");
    }
    else
    {
        printf("is not text file\n");
    }
    
    ...

prints

    is not text file

Depending upon your language of choice this kind of thing usually results in an NPE or the abrupt termination of your program, but in Objective-C nothing happens.

The reason nothing happens in Objective-C is because the semantics of sending a message to nil are well defined.

If you send a message which returns nothing, i.e., void, nothing happens.

if you send a message which returns a reference to object to nil then you get back nil.

If you send a message which returns something other than an object to nil you get back 0 or its equivalent

In the example above the call to lastPathComponent on nil returns nil.

The call to hasSuffix on nil returns false.

The downside to this is that you can, on occasion, spend quite a bit of time wondering why nothing is happening only to eventually discover that some variable had the value nil when it ought not to have.

The designers of Swift have decided to be helpful and eliminate this downside by making it both impossible to forget to initialize variables and impossible to initialize them to nil in the Objective-C style.

1.0 Constants And Variables

You can declare a constant in Swift like this

    let constantCod: String = "a fish"

Swift supports type inference so you can omit the type if you wish

    let constantCod = "a fish"

As you might expect given that it is a constant you cannot assign another value to constantCod once it has been initialized.

In addition if the constant refers to a compound value, an instance of a struct for example, the value itself is immutable.

You declare a variable in Swift in the same way but using var instead of let.

    var cod: String = "a fish"

and without the type.

    var cod = "a fish"

You can assign another value to a variable in the usual way

    cod = "another fish"

If you are declaring a constant or a global variable you must specify a value in the declaration, but if you are declaring a local variable you can omit the initializer if you wish in which case you must specify the type.

If you declare a local variable without an inititializer you cannot access that variable until it has been explicitly initialized.

So doing this

    var cod: String

    ...

    // compiler error here: Variable 'cod' used before being initialized 
    var uppercaseCod = cod.uppercaseString 
    
    
    println("uppercaseCod == \(uppercaseCod)")

gets you a compiler error, whereas, doing this

    var cod: String

    cod = "a fish"

    var uppercaseCod = cod.uppercaseString

    println("uppercaseCod == \(uppercaseCod)")

prints

    uppercaseCod == A FISH

as you might expect.

2.0 The Optional Type

While this is all very helpful, what if you really, really need to declare a variable which has a value except when it doesn’t ?

The answer is to declare the variable to have the type

    Optional<T>

where T is the type of the variable when it does have a value.

For example

    var optionalCod: Optional<String>

The generic type Optional<T> is defined in the Swift library.

Swift provides syntactic sugar for this in the form of question mark (‘?’) suffix to the type of the variable so you can write the above as

    var optionalCod: String?

3.0 Assignment

You can assign three types of thing to a variable of type Optional<T>

  • a value of type T

  • nil which indicates that the variable has no value, or

  • another value of type Optional<T>

Omitting the initializer when declaring an Optional variable

    var optionalCod: String?

is equivalent to explicitly initializing it to nil

    var optionalCod: String? = nil

If you assign one Optional<T> value to another the value will be copied. so

    var cod : String? = "a fish"
    var dab : String? = cod
    
    println("cod == \(cod)")
    
    cod = nil
    
    println("cod == \(cod)")
    println("dab == \(dab)")

prints

    cod == a fish
    cod == nil
    dab == a fish

4.0 Accessing The Value

Now you have succeeded in declaring a variable which may or may not have a value how do you get at the value, assuming there is one ?

In Swift parlance this is termed unwrapping and there are multiple ways of doing it.

4.1 Forced Unwrapping

If you are absolutely certain that there is a value in the variable you can use forced unwrapping which simply involves adding an exclamation mark (!) as a suffix

    optionalCod!

This is definitely the way to go if you like your programs to terminate abruptly when something goes wrong because if there is no value in the variable that is exactly what happens

So doing this

    var optionalCod: String?

    ...
    
    var cod : String = optionalCod!

gets you this at runtime

    fatal error: Can't unwrap Optional.None

and everything stops.

4.2 Look Before You Leap

Fortunately for those of us of a more nervous disposition it is possible to check whether an Optional variable contains a value before potentially exploding it using the bang operator !

For example

    var optionalCod: String?
    
    ...

    if optionalCod
    {
        println("uppercase optionalCod == \(optionalCod!.uppercaseString)")
    }
    else
    {
        println("optionalCod is nil")
    }

4.3 Optional Binding

Alternatively you can combine the checking and the unwrapping like so

    var optionalCod: String?

    if let cod = optionalCod
    {
        println("uppercase cod == \(cod.uppercaseString)")
    }
    else
    {
        println("optionalCod is nil")
    }

4.4 Optional Chaining

If you are invoking a method on the value in an Optional variable you can add a question mark (‘?’) suffix to the variable and then invoke the method, so given

    var path: String?

you can do

    path?.componentsSeparatedByString("/")

If the variable contains a value then the method will be invoked. If it is nil then nothing happens.

The value of this expression will of necessity be of type Optional<T> where T is the type of the value returned by the method being invoked

    var path: String?

    ...
    
    let parts: Optional<String[]> = path?.componentsSeparatedByString("/")

    ...

Given that the type of the expression is of type Optional<T> you might think that if you want to call a method on the result you need to use the ‘?’ suffix again like so

    path?.componentsSeparatedByString("/")?.reverse()

but if you try this you get a compiler error, specifically

    path?.componentsSeparatedByString("/")?.reverse()
    Operand of postfix '?' should have optional type: type is 'String[]'

which is a bit puzzling at first.

In fact while it is true that in isolation the type of

    path?.componentsSeparatedByString("/")

is

    Optional<String[]>

in the context of a chain of method calls if the Optional variable has no value then the ? operator shortcuts the entire chain and returns immediately.

So at runtime at the point the method reverse is being called the ? operator has already opened the box and found a
String[] value in it rather than nil and it has called componentsSeparatedByString on it and the type of

    path?.componentsSeparatedByString("/")

really is

    String[]

Another way of looking at it is that adding a postfix ? is equivalent to doing this

    let path  : String?
    var result: (String[])?
    
    // ...
    
    if let p : String = path
    {
        let parts   : String[] = p.componentsSeparatedByString("/")
        let reversed: String[] = parts.reverse()
    
        result = reversed
    }
    else
    {
        result = nil
    }

from which it is clear that the result of calling componentsSeparatedByString really is a String[].

Which is all a very long and round about way of you do not actually need the second postfix ? at all. You can simply do this

    path?.componentsSeparatedByString("/").reverse()

You can chain as many methods together as you can find and you still only need the initial ‘?’ assuming of course that none of the methods themselves explicitly return Optional values.

If the last method in the chain returns a value of type Optional<T>, for example

    path?.componentsSeparatedByString("/").reverse()[0].toInt()

where the method toInt returns

    Optional<Int>

you might think that the result of the method chain expression would be

    Optional<Optional<T>>

but it is in fact

    Optional<T>

which has the merit of consistency and simplicity since you only ever have to unwrap the resulting value once

4.5 Implicit Unwrapping

If you declare an Optional variable then, as we have seen, you need to unwrap it one way or another each time you want to use the value.

If you are in a position where you are certain that the Optional variable will definitely have a value each time you use it then you can avoid the need to explicitly unwrap it at each point of use
by declaring it like this

    var optionalDab: String!

adding a postfix exclamation mark (!) to the type rather than a question mark (?).

You can then refer to it directly when using without explicitly unwrapping it.

It is still being unwrapped implicitly using forced unwrapping so if your model of the variable’s usage is incorrect and there is in fact some point at which it can be used before it has been initialized you will find out all about it at runtime.

5.0 Optional Constants

You can, if you want, declare constants with Optional types but after the novelty has worn off they turn out not to be very interesting at all.

Since the only thing you can do with a constant is initialize it or use it you can either have a constant which is guaranteed to be nil

    let constantDab: String?

or one that is guaranteed to have a value

    let constantDab: String? = "an optional fish"

and thats it.

6.0 Optional Globals

You can declare a global variable with an Optional value.

This can be useful if you do not want to or cannot initialize it at the point it is declared but it is guaranteed to have been initialized before it is used.

This case also allows you to take advantage of implicit unwrapping as described above but the caveat about runtime exceptions also applies.

    // declaration
    
    var globalOptionalEel: String!
    
    ...
    
    // initialization
    
    globalOptionalEel = "global eel"
    
    ...
    
    // usage with implict unwrapping plus chance of runtime exception
    
    let constantEel: String = globalOptionalEel

Copyright (c) 2014 By Simon Lewis. All Rights Reserved.

Unauthorized use and/or duplication of this material without express and written permission from this blog’s author and owner Simon Lewis is strictly prohibited.

Excerpts and links may be used, provided that full and clear credit is given to Simon Lewis and justanapplication.wordpress.com with appropriate and specific direction to the original content.

June 27, 2014

So Swift Then ? Or Wot No Brackets ?

So Swift is essentially Objective-C without the C and without the bracket message sending syntax and with some new stuff and some changed stuff.

Well the C is no loss but the brackets are the best bit so what new stuff do we get to compensate for their disappearance ?

In no particular order

  • tuples

  • a first class enum type

  • a first class struct type

  • operator functions and custom operators

  • range operators

  • subscript operators

  • optional values

  • generics

  • a super switch

  • a plethora of options for parameter lists

and

    much much more

as it always says on the posters.


Copyright (c) 2014 By Simon Lewis. All Rights Reserved.

Unauthorized use and/or duplication of this material without express and written permission from this blog’s author and owner Simon Lewis is strictly prohibited.

Excerpts and links may be used, provided that full and clear credit is given to Simon Lewis and justanapplication.wordpress.com with appropriate and specific direction to the original content.

Blog at WordPress.com.

%d bloggers like this: