How to make `ExpressibleByStringLiteral` init either failable somehow or throws?

struct Foo: ExpressibleByStringLiteral {
    init(stringLiteral value: String) /* throws :( not allow? */ {
        guard value == "good" else {
            // how to fail?
            // neither failable or throws seem to be allowed?
            fatalError("Ha? what to do here, want to fail somehow, not crash!!!")
        }
        // okay, we are good ...
    }
}

basically Foo init by string literal only works for some string values, else it needs to fail somehow.

1 Like

fatalError is the best you can do for now. Hopefully optimizer improvements will eventually allow literals to be evaluated as compile‐time constants, which would elevate the fatalError to an outright build failure.

2 Likes

How would a throwing assignment work? Where should you put try?

do {
  // here?
  try let foo: Foo = "good"
  // or maybe here?
  let foo: Foo = try "good"
} catch { }

I don't see a workable solution from the syntactic standpoint alone.


A solution that may work for your use case: mimicking a failable initializer.

public struct Foo {}

extension Optional: ExpressibleByStringLiteral,
                    ExpressibleByUnicodeScalarLiteral,
                    ExpressibleByExtendedGraphemeClusterLiteral where Wrapped == Foo {
  public init(stringLiteral value: String) {
    guard value == "good" else {
      self = nil
      return
    }
    // okay, we are good ...
    self = Foo()
  }
  
  public init(unicodeScalarLiteral value: String) {
    self = .init(stringLiteral: value)
  }
  
  public init(extendedGraphemeClusterLiteral value: String) {
    self = .init(stringLiteral: value)
  }
}
let foo: Foo? = "bad"   // assigns nil
let bar: Foo? = "good"  // assigns Foo()
2 Likes

One thing you could do is make Optional<Foo> conform to the Expressible protocol, rather than Foo itself.

3 Likes
Terms of Service

Privacy Policy

Cookie Policy