Surprising behavior from SE-0213

Why would a value type provide an unlabeled initializer from its own type?

Well, whatever. I think there’s a bug here, because SE-0213 seems fairly unambiguous about this always using the literal initializer, so it should not be considering failable initializers in optional context. If people want to separately pitch reverting SE-0213 because they misunderstood the proposal, they’re welcome to do so.

5 Likes

I actually wanted to make TimeOfDay(...)?.hour an invalid syntax, but that would have resolved in source compatibility problem, that's why the decision was made to keep supporting it.

I think we should’ve talked about that. Presumably this was already only done under a new language compatibility version.

Yeah, that's exactly how it is.

I realized today that I'm using the Swift 5 compiler in Swift 4.2 mode, so I think this issue affects both syntax modes.

I don't know if that's relevant to @John_McCall's "new language compatibility version" comment.

This makes sense as this is (partly) a runtime behavior, so you get all bug fixes and new runtime behavior regardless of the language mode your project has.

I don't think there's any language-runtime involvement here. It should be totally determined by language compatibility mode.

Was the consensus there is a bug (or bugs) here?

  1. The behavior change affects Swift-4 source mode.
  2. The compiler's initializer selection is affected by the surrounding context (e.g. being part of an optional chain).

Also, should the compiler emit and error (or at least a warning) if you try to implement a no-label initializer along side a literal initializer? Allowing both results in really confusing behavior:

struct TimeOfDay: ExpressibleByStringLiteral {
    init(_ string: String) {
        print("using init(_:)")
    }

    init(stringLiteral: String) {
        print("using init(stringLiteral:)")
    }
}

TimeOfDay("00:00") // prints "using init(stringLiteral:)"
TimeOfDay.init("00:00") // prints "using init(_:)"
1 Like

I think both (1) and (2) are bugs. I don't think that warning would be appropriate because it's common to have both coercion initializers and literal initializers.

I think if it's common to have both, we would need to revisit SE-0123, because that proposal makes it pretty difficult for both to coexist.

Edit: To clarify, I only meant the compiler should emit a warning if the no-label initializer has the same effective signature as the literal initializer. You would of course still be free to define init(_ x: SomeOtherType)

It took probably too long, but I finally filed SR-10816 for (1).

I'm unable to reproduce (2) anymore. The compiler appears to consistently choose the string literal initializer now. (Maybe I was using Xcode 10.2.0 before, vs 10.2.1 now?) :man_shrugging: