Initializers on enums

Hi All.

I'd like to log to the console every time an error is used. I thought it would be easy to just create an initializer on an enum and do a print inside there, like so:

public enum MyErrors : Error {
    case invalidArgument(String)       // message
    
    init() {
        print("Error!")
    }
}

However, when I try to compile this, I get the error:

'self.init' isn't called on all paths before returning from initializer

I clearly don't understand enums. How can I call self.init from init?
Any help is greatly appreciated.

Using one of the cases to initialize an enum isn't going to call the initializer. The initializer must be called directly, like so:

let e = MyErrors()

However, for this to work the initializer needs to choose one of the cases itself. Something like that:

init() {
    self = .invalidArgument("hello")
}

This will quiet the error you see, although I know this is not really what you want. There's unfortunately no way to call code when you're using one of the cases to initialize the enum.

You can actually simulate this if you really need to:

public enum MyErrors : Error {
    case _invalidArgument(String)       // message
    
    static func invalidArgument(_ s: String) -> MyErrors {
        print("Error!")
        return _invalidArgument(String)
    }
}

The syntax from the caller side will be exactly the same.

This is a really key limitation. Users will always be able to use .invalidArgument to create an error of this type.

If you want to do this, you'll likely be better served by making your error a struct, instead of an enum.

Thanks for your answers. Since I generally thing it's a bad thing to go against the grain of the tool, it's probably a better idea to create a custom throwing function to put everything in.

Terms of Service

Privacy Policy

Cookie Policy