Optionals in switch statements


(Matteo) #1

I’m trying to make the best use of swift’s switch statement while converting some old code from obj-c.

Imagine a method that takes two optional strings representing file names:

func updateFileFrom(from : String?, to: String?)

If both strings are nil, then it does nothing.
If both are non nil AND are equal it also does nothing
If both are non-nil and not equal it renames the file
If from is not nil, but to is nil, it deletes the file.
If from is nil, but to is not-nil it creates a file.

Here is my original implementation as a straight conversion using only if:

func ifs_updateFileFrom(from : String?, to: String?)
{
    if from == nil && to == nil {
        print("Nothing to do, both are nil")
    } else if from != nil && to != nil {
        if from == to {
            print("Nothing to do, both are non-nil and equal")
        } else {
            print("Renaming \(from!) to \(to!)")
        }
    } else if to == nil {
        print("Deleting \(from!)")
    } else {
        print("Creating \(to!)")
    }
}

So I’ve had a go at using a switch statement to make it more readable:

func switch_updateFileFrom(from : String?, to: String?)
{
    switch (from, to) {
    case (.None, .None):
        print("Nothing to do, both are nil")
    case (.Some, .Some) where from == to:
        print("Nothing to do, both are non-nil and equal")
    case (.Some, .Some):
        print("Renaming \(from!) to \(to!)")
    case (.Some, .None):
        print("Deleting \(from!)")
    case (.None, .Some):
        print("Creating \(to!)")
    }
}

It seems reasonable to me and clearer, but I don’t really like accessing the from and to variables within it, it just doesn’t feel right compared to ‘normal’ switch statement

i.e consider this example from the swift book:

let anotherPoint = (2, 0)

switch anotherPoint {
case (let x, 0):
    print("on x-axis with x value of \(x)")
case (0, let y):
    print("on y-axis with y value of \(y)")
case let (x, y):
    print("Somewhere else at (\(x), \(y))")
}

The switch statement is entirely self-referential with regard to the internally bound values of x and y, it has no need to access anotherPoint directly.

Is there a way to write my switch-based method that does not access from and to directly, but is also as clear?

Thanks


(Loïc Lecrenier) #2

Hi Matteo,

I would write it like that:

func switch_updateFileFrom(from : String?, to: String?)
{
    switch(from, to) {

    case (nil, nil):
        print("Nothing to do, both are nil")

    case let (x?, y?) where x == y:
        print("Nothing to do, both are non-nil and equal")

    case let (x?, y?):
        print("Renaming \(x) to \(y)")

    case let (x?, nil):
        print("Deleting \(x)")

    case let (nil, y?):
        print("Creating \(y)")
    }
}

“x?” is syntactic sugar for “.Some(x)"
“nil” is a literal equivalent to “.None” (in this case)

Loïc

···

On Jun 29, 2016, at 12:42 PM, Matteo via swift-users <swift-users@swift.org> wrote:

I’m trying to make the best use of swift’s switch statement while converting some old code from obj-c.

Imagine a method that takes two optional strings representing file names:

func updateFileFrom(from : String?, to: String?)

If both strings are nil, then it does nothing.
If both are non nil AND are equal it also does nothing
If both are non-nil and not equal it renames the file
If from is not nil, but to is nil, it deletes the file.
If from is nil, but to is not-nil it creates a file.

Here is my original implementation as a straight conversion using only if:

func ifs_updateFileFrom(from : String?, to: String?)
{
   if from == nil && to == nil {
       print("Nothing to do, both are nil")
   } else if from != nil && to != nil {
       if from == to {
           print("Nothing to do, both are non-nil and equal")
       } else {
           print("Renaming \(from!) to \(to!)")
       }
   } else if to == nil {
       print("Deleting \(from!)")
   } else {
       print("Creating \(to!)")
   }
}

So I’ve had a go at using a switch statement to make it more readable:

func switch_updateFileFrom(from : String?, to: String?)
{
   switch (from, to) {
   case (.None, .None):
       print("Nothing to do, both are nil")
   case (.Some, .Some) where from == to:
       print("Nothing to do, both are non-nil and equal")
   case (.Some, .Some):
       print("Renaming \(from!) to \(to!)")
   case (.Some, .None):
       print("Deleting \(from!)")
   case (.None, .Some):
       print("Creating \(to!)")
   }
}

It seems reasonable to me and clearer, but I don’t really like accessing the from and to variables within it, it just doesn’t feel right compared to ‘normal’ switch statement

i.e consider this example from the swift book:

let anotherPoint = (2, 0)

switch anotherPoint {
case (let x, 0):
   print("on x-axis with x value of \(x)")
case (0, let y):
   print("on y-axis with y value of \(y)")
case let (x, y):
   print("Somewhere else at (\(x), \(y))")
}

The switch statement is entirely self-referential with regard to the internally bound values of x and y, it has no need to access anotherPoint directly.

Is there a way to write my switch-based method that does not access from and to directly, but is also as clear?

Thanks

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users