#if / #endif brackets around protocols

Aligning the implementation with the proposal (rather than the other way around) would make it less subtle, and it bears mentioning even if it's gnarly to implement that the plan of record does not today include any timeline for deprecation.

As far as I'm concerned, this is the "forever" language we want, which not coincidentally but explicitly exists to address the specific use case you actively asked about.

This is what I don't understand. Leaving compiler compatibility aside... why do we want two ways to express this feature with the second way being so "implicit"?

...for the use case you asked about, which as you said cannot be served by @retroactive.

I mean I do not understand the need for this trick to be "a forever" feature...

This is not nice:

#if compiler(>=6.0)
extension Foo: @retroactive Bar {
  // ... conformance implementation ...
}
#else
extension Foo: Bar {
  // ... same conformance implementation ...
}
#endif

but at least it's visible (being explicit) and eventually I could get rid of it, say in two years time when compatibility with the old compiler that doesn't support retroactive is no longer a concern.

Ah, you didn't specify that your compile-time conditional is compiler version, merely "someCompilationSwitch".

In the general case, whether Bar is a retroactive conformance or not could depend on something else at compile time. For example, Bar could be polyfilled in the same module on one platform but provided by a third-party library on another platform. You would then need an alternative to @retroactive as a forever feature.

Indeed, I was thinking of doing something unrelated to compiler compatibility:

#if useModules // my setting
import Module1 // for Type1
import Module2 // for Protocol2
#endif
...

#if useModules
extension Type1: @retroactive Protocol2 {
    ...
}
#else
extension Type1: Protocol2 {
    ...
}
#endif
I miss C preprocessor...
#if someCondition
#define retroactive @retroactive
#else 
#define retroactive // empty
#endif

extension Type1: retroactive Protocol2 { ... }

So primitive but so powerful at the same time.

2 Likes

On the other hand, the explicit spelling @retroactive makes it clearer that something unsafe is going on. An extension stating conformance to a fully-qualified protocol name gives no hint that the construction is potentially unsafe.

3 Likes

For sure, @retroactive has enough advantages that it was worth introducing a new syntax.

I think there is a fairly straightforward reorganization of the logic here that handles all permutations without much change and virtually no additional code (and is incidentally also easier to strip out, and does almost no work in the common case where the extended type itself isn't module qualified). Have not tested but will do so and chuck it over the fence at some point if it seems to pan out.

This can be simplified to:

#if whateverCondition
extension Foo: @retroactive Bar {}
#else
extension Foo: Bar {}
#endif
extension Foo {
  // ... conformance implementation ...
}

You don't need to repeat the entire implementation twice.

2 Likes

BTW, this:

protocol Retroactive {}

extension Array: Retroactive & Identifiable {
    public var id: Int { 0 }
}

also silences the retroactive warning... Not sure if that's by design (most likely not!)

@Slava_Pestov has fixed that bug.

Good!

Consider this alternative:

protocol MyIdentifiable: Retroactive, Identifiable {}

extension Array: MyIdentifiable { // no warning

It would make it a bit heavier to silence the warning (but that's good!)

It'd also be reasonably compatible (Retroactive is a marker protocol on newer compilers and just a dummy protocol on old compilers).

I missed that proposal discussion, but the idea of making qualification workaround temporary was there: