[swift-evolution] Overloading Generic Types

David Sweeris davesweeris at mac.com
Wed Feb 22 17:39:04 CST 2017


> On Feb 22, 2017, at 3:00 PM, Slava Pestov <spestov at apple.com> wrote:
> 
> 
>> On Dec 23, 2016, at 12:32 PM, David Sweeris via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> (I feel like I’ve already written this... I looked through my sent mail and didn’t see anything, but my sincerest apologies if I started this thread a month ago and forgot about it or something.)
>> 
>> I no longer recall exactly what first made me want to do this (probably something in my on-going “teach the compiler calculus” project), but I’ve been thinking lately that it could be quite handy to overload types themselves based on the value of generic parameters. As a somewhat contrived example:
>> struct Array <T> { /*everything exactly as it is now*/ }
>> struct Array <T> where T == Bool { /* packs every 8 bools into a UInt8 for more efficient storage */ }
>> 
>> We can already do this with functions… Conceptually this isn’t any different.
> 
> Actually this is a major complication because of the runtime generics model. Imagine you have a function that takes a T and constructs an Array<T>. Now it has to do dynamic dispatch to find the right type metadata (is it the “generic” Array<T>, or the specialized Array<Bool>?)

Wouldn’t that get resolved at compile time? Oh! Wait, are you talking about this?
func bar <T> (_ x: T) -> String { return "any T" }
func bar <T> (_ x: T) -> String where T: CustomStringConvertible { return "\(x)" }
func foo <T> (_ x: T) -> String { return bar(x) }
and “foo()" always returns “any T” because by the time we get to `bar`, T isn’t known to be constrained to anything at compile time?

In any case, since the point is to optimize the type's implementation rather than change its behavior, I think the only result is that your array maker function would return an “unoptimized” array. I’m not sure… I’d have to think about it some more. And come up with a better illustration, since it’s been pointed out that my original example isn’t a particularly good idea.

>> As long as the specific version exposes everything the generic version does (easy for the compiler to enforce), I think everything would just work (famous last words).
> 
> What if another module defines an extension of Array<T>, but not ‘Array<T> where T == Bool’?

IIUC, that shouldn’t matter because the specific version would have to have the same public interface as the generic version.

>> In this example, the subscript function would need to extract the specified bit and return it as a Bool instead of simply returning the specified element. The `Element` typealias would be `Bool` instead of `UInt8`, which would mean the size/stride might be different than expected (but that’s why we have `MemoryLayout<>`).
>> 
>> Anyway, because generic structs & functions already can’t make assumptions about a generic argument (beyond any constraints, of course), I think this should be in phase 2… but I’m quite hazy on how generics work once the code’s been compiled, so maybe not.
> 
> Another way of modeling this might be to define a protocol, say “RepresentableInArray”, which implements get and set methods that take a pointer to a buffer, and an index. A default implementation in a protocol extension would just load and store the value. ‘Bool’ would define its own conformance which performs bitwise operations.
> 
> However I think this is out of scope for stage 2 — it doesn’t fix any obvious major shortcoming in the language, it vastly complicates the implementation and it’s not required to achieve our ABI stability goals.

Fair enough. Is there a stage 3, or does that mean “out of scope until Swift 4.1+”?

- Dave Sweeris
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170222/3030714b/attachment.html>


More information about the swift-evolution mailing list