Implementation issues with SE-0283 (Tuples are EHC)

I wanted to post this in the recent Status of SE-0283? (Tuples Conform to Equatable, Comparable, and Hashable) , but figured it might be better suited for a separate compilerish thread.

The two main issues that I've had trouble coming to terms with are 1. the assembly needed in the runtime and 2. the lack of hooks in older runtimes to implement backwards compatibility in a "clean" or non-hacky way in my eyes.

The first issue is only really an issue on platforms Swift is not currently supported on because I've worked my way through designing the assembly needed to work on Darwin, Windows, and a subset of Linux. Shortly afterwards I realized I could do the same thing the compatibility libraries do when resolving relative references (which is why the data structures needed for these conformances are in assembly to begin with) by having a constructor inject the relative references. The obvious downside to this is that there is a small startup cost, but allows the implementation to rely solely on C++ and no assembly.

The second issue is a little more difficult for me. When a Swift program uses a conformance (either by passing in a value in a generic constrained function, constructing a type with protocol constraints, etc.), depending on the conformance we may need to create a new witness table at runtime. In the case of tuples, we do need to make a new witness table with a list of all the element witness tables. We need to directly reference the data structure that models this conformance when generating a new witness table. Because this feature is new for the runtime, older runtimes don't have this conformance data structure to reference, so the compiler/runtime has 2 options. Either the compiler emits a stub function within a program that essentially checks the runtime version and dlsyms the correct data structure (I'm unsure if dlsym can even find the backward conformance), or the runtime already has a hook that does this dlsym and gives us back the right thing. There's a set list of runtime functions that are already hooked, but only 1 or maybe 2 of them could work in this case of generating a new witness table. That's great for the backward clients because these conformances work a little differently for them, but applications deploying to those older targets but running on the newer runtime will pay a performance cost, again because of the implementation difference between the conformances on new vs. old.

Perhaps I'm overcomplicating a lot of this (or all of it), and if I am I apologize. I've been considering maybe it's just better we wait until general conformances on non-nominal so that things aren't as special cased and the compiler has more information to be able to solve some of these issues for us. I initially wrote this for the evolution thread, but since moved it over here. Please ask if you need more detail!

15 Likes