bekditlevsen.dk

SE-0380, if and switch expressions

UPDATE, January 21, 2023

SE-0380 was just accepted. Yay! :-)

Example

Let's start with a quick example of one of the things that this proposal allows you to do:

Instead of:

extension MenuItem {
    var localizedTitle: String {
        switch self {
        case .customerLookup: 
            return L10n.Menu.customerLookup
        case .customerSignup: 
            return L10n.Menu.customerSignup
        case .addBasketComment: 
            return L10n.Menu.comment
        case .addBasketDiscount: 
            return L10n.Menu.addBasketDiscount
        ...
    }
}

you can now write:

extension MenuItem {
    var localizedTitle: String {
        switch self {
        case .customerLookup: 
            L10n.Menu.customerLookup
        case .customerSignup: 
            L10n.Menu.customerSignup
        case .addBasketComment: 
            L10n.Menu.comment
        case .addBasketDiscount: 
            L10n.Menu.addBasketDiscount
        ...
    }
}

Skipping the 'ceremony' of requiring a return statement in many situations where it is inferable, is exactly what this proposal is about.

Links

Proposal

Swift Evolution discussion

As the title suggests, this proposal adds support for using if- and switch-statements as expressions under certain circumstances.

From the proposal:

  • Returning values from functions, properties, and closures;
  • Assigning values to variables; and
  • Declaring variables.

Furthermore the following criteria must be satisfied:

Each branch of the if, or each case of the switch, must be a single expression.

A side note on readability

One of the things I love most about Swift is it's readability. But I do not think that readability suggests verbosity. In many cases I find that terseness improves on readability.

One example of this is the if let shorthand introduced with Swift 5.7 from SE-0345 by Cal Stephens. I honestly thought that this functionality was a bit unnecessary, but after it's release I have come to love it. It avoids duplication of labels that did not really add anything to the readability. You need to know of this new syntax, but I find that it's so natural that when you read it, you'll know what it's about.

switch expressions

A very common pattern in the code bases I work with is mapping enums. We have many, many examples of mapping enums to localizable strings, mapping enums to colors and mapping enums to other enums.

In most of these cases the mapping is split into a function or a calculated property, so that it basically looks like this:

extension InvoiceMode {
    var buttonTitle: String {
        switch self {
        case .creditNote:
            return L10n.InvoicePayment.sendCreditNote
        case .invoice:
            return L10n.InvoicePayment.sendInvoice
        }
    }
}

or

extension MenuItem {
    var localizedTitle: String {
        switch self {
        case .customerLookup: return L10n.Menu.customerLookup
        case .customerSignup: return L10n.Menu.customerSignup
        case .addBasketComment: return L10n.Menu.comment
        case .addBasketDiscount: return L10n.Menu.addBasketDiscount
        ...
    }
}

In all of these mappings I have always felt that the repeated return statements didn't add to the readability at all.

I can see from the switch statement inside a function body that I am mapping from one domain to another - and all I care about is the source and destination values.

SE-0380 exactly allows us to skip the return statements in these situations, so that the above becomes:

extension InvoiceMode {
    var buttonTitle: String {
        switch self {
        case .creditNote:
            L10n.InvoicePayment.sendCreditNote
        case .invoice:
            L10n.InvoicePayment.sendInvoice
        }
    }
}

or

extension MenuItem {
    var localizedTitle: String {
        switch self {
        case .customerLookup: L10n.Menu.customerLookup
        case .customerSignup: L10n.Menu.customerSignup
        case .addBasketComment: L10n.Menu.comment
        case .addBasketDiscount: L10n.Menu.addBasketDiscount
        ...
    }
}

I just love being able to skip the extra ceremony here and focus on mapping. :-)

if expressions

I don't think that I will be using if expressions quite as much as switch expressions, but I suspect that I would be using it within closures, function bodies and properties like in the examples above.

Both statements can also be used as expressions when declaring variables and assigning to variables. I do think that I will use those a bit less, but they definitely have their uses.

From the proposal:

let bullet =
     if isRoot && (count == 0 || !willExpand) { "" }
     else if count == 0 { "- " }
     else if maxDepth <= 0 { "▹ " }
     else { "▿ " }
 

Please have a look at the proposal itself - and at the discussion topic on the SE forums for more details.

Tagged with: