> On Feb 22, 2017, at 3:39 PM, David Sweeris <[email protected]> wrote:
>
>>
>> On Feb 22, 2017, at 3:00 PM, Slava Pestov <[email protected]
>> <mailto:[email protected]>> wrote:
>>
>>
>>> On Dec 23, 2016, at 12:32 PM, David Sweeris via swift-evolution
>>> <[email protected] <mailto:[email protected]>> 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
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution