> 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