> On Feb 22, 2017, at 3:39 PM, David Sweeris <daveswee...@mac.com> wrote:
> 
>> 
>> On Feb 22, 2017, at 3:00 PM, Slava Pestov <spes...@apple.com 
>> <mailto:spes...@apple.com>> wrote:
>> 
>> 
>>> On Dec 23, 2016, at 12:32 PM, David Sweeris via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@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?

I mean this:

func foo<T>(t: T) -> [T] {
  return [t]
}

foo(t: false) // is this the ‘optimized’ or ‘unoptimized’ version?
foo(t: 123)

> 
> 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.

Ok then, what if I have:

func foo<T>(x: T, y: T) {

}

And I call foo() with an ‘optimized’ Array<Bool> and ‘unoptimized’ Array<Bool>. 
That won’t work at all, since it’s only passing one type metadata parameter for 
T, and not one for each value. So which one would it pass?

> 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.

But with the extension in place, now they have different interfaces, because 
the optimized version won’t have the extension’s methods in it.

> 
>>> 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+”?

The latter.

Slava

> 
> - Dave Sweeris

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to