How do I declare that a computed property 'throws' in Swift?
Asked Answered
N

4

80
class SomeClass {
  var someProperty: Int {
    throw Err("SNAFU")
  }
}

For code like the above, the swift binary complains 'error is not handled because the enclosing function is not declared 'throws'.

How do I declare that 'someProperty' 'throws' in the above?

class SomeClass {
  var someProperty throws: Int {
  }
}

and

class SomeClass {
  var someProperty: throws Int {
  }
}

and

class SomeClass {
  var someProperty: Int throws {
  }
}

don't seem to work.

Nab answered 2/10, 2015 at 1:46 Comment(0)
D
114

This functionality is added for read-only computed properties in Swift 5.5 as part of SE-0310 (included in Xcode 13).

Based on SE-0310, the syntax would be:

class SomeClass {
  var someProperty: Int {
    get throws {
      throw Err("SNAFU")
    }
  }
}

Here is the previous answer for versions of Swift prior to 5.5:

You cannot throw from a computed property. You must use a function if you want to throw. The Declarations section of the Language Reference part at the end of The Swift Programming Language only lists throws (and rethrows) as a keyword for function and initializer declarations.

Delladelle answered 2/10, 2015 at 1:51 Comment(4)
Thank you for the the language reference; it is pretty convincing. I realize this is not the original issue i asked, but in my scenario, I have a container type and I only want to implement 'hashValue' when each of the elements are themselves hashable. Do you happen to know what I can do to workaround this?Nab
Is it reasonable to make your container a generic type that only works with Hashable elements in the same way that swift Dictionary keys must be Hashable? If not I suppose you might have to do some work to come up with a hash function in the case that your elements aren't hashable since the Hashable protocol does not allow for a nil response and you can't throw. You could also use fatalError() if that's appropriate.Delladelle
@Nab This surely comes too late, but remember you can add extensions that constrain. For example, if you had a container defined like struct Container<Element> {} you could then add an extension like extension Container where Element: Hashable {} and define your computed property in the extension. The computed property will only be available if the Element type inside a Container instance is Hashable.Wonderstricken
I don't think the Swift docs really spell this out, but check out "Type Constraints" and "Where Clauses" sections of the Generics docs.Wonderstricken
A
62

While it's not possible (yet) to throw from computed properties in Swift, I found Chris Lattner himself adresses this very same question on one of Apple Developer Forums threads:

We agree that you should be able to mark the getters and setters as "throws" in subscripts and computed properties, but haven't gotten there yet. We are likely to support this at some time, but it isn't clear if it will make it in time for Swift 2.

Alejoa answered 15/11, 2015 at 20:32 Comment(14)
Nice to see Chris' comments on this.Scatterbrain
Note that this has not changed in swift 3.Spermiogenesis
Note that this has not changed in Swift 4.Bathsheeb
Note that this has not changed in Swift 4.1.Phrase
Note that this has not changed in Swift 4.2.Besot
Note that this has not changed in Swift 5.0.Zipporah
Note that this has not changed in Swift 5.1Ratable
Note that this has not changed in Swift 5.2Rubdown
Note that this has not changed in Swift 5.3Singley
Hope they support it in Swift 6 (I'll be the format breaker here).Alexandros
Note that this has not changed in Swift 5.4Roshan
Note that this has changed in Swift 5.5.Lafrance
@IulianOnofrei only partlyLigroin
Note that this thread is awesome and is now completed.Prostatectomy
I
4

In case someone needs to declare a throwing and/or async computed properties as part of protocol requirements:

1. Throwing

protocol DatabaseProtocol {
    var isEmpty: Bool { get throws }
}

struct Database {
    var isEmpty: Bool {
        get throws {
            ...
        }
    }
}

2. Async

protocol DatabaseProtocol {
    var isEmpty: Bool { get async }
}

struct Database {
    var isEmpty: Bool {
        get async {
            ...
        }
    }
}

3. Throwing and Async

protocol DatabaseProtocol {
    var isEmpty: Bool { get async throws }
}

struct Database {
    var isEmpty: Bool {
        get async throws {
            ...
        }
    }
}
Interweave answered 14/10, 2023 at 6:34 Comment(0)
D
3

Let me suggest a workaround: a property can be declared as having type of Result<DesiredPropertyType, Error>. This way it can be accessed like this:

do {
    try self.failableProperty.get()
} catch {
    ...
}

get() is a built-in method of Swift's Result.

UPDATE: this is getting addressed in Swift 5.5 with "effectful read-only properties": https://github.com/apple/swift-evolution/blob/main/proposals/0310-effectful-readonly-properties.md.

Definitely answered 11/2, 2020 at 10:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.