> On Feb 18, 2017, at 3:16 PM, Haravikk <[email protected]> wrote:
> 
> 
>> On 18 Feb 2017, at 16:28, Matthew Johnson <[email protected] 
>> <mailto:[email protected]>> wrote:
>> 
>>> 
>>> On Feb 18, 2017, at 4:54 AM, Brent Royal-Gordon via swift-evolution 
>>> <[email protected] <mailto:[email protected]>> wrote:
>>> 
>>>> On Feb 18, 2017, at 2:18 AM, Haravikk via swift-evolution 
>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>> 
>>>> This is an idea I had while working with collections, and is particularly 
>>>> inspired by those that use common index types.
>>>> 
>>>> Consider for example an array; for indices it simply uses an integer, 
>>>> however, while this is a perfectly valid type to use it opens up the 
>>>> possibility of integers from any number of different sources being passed 
>>>> in by mistake and causing run-time errors. The same is true for wrapping 
>>>> types that use AnyIndex, or really any type that uses Any* to hide 
>>>> underlying types, as on the surface all AnyIndex instances give the 
>>>> illusion of being compatible when they're not, and will only produce 
>>>> errors at run-time when a conflict arises.
>>>> 
>>>> The idea to combat this is simple; a new attribute that can be applied to 
>>>> a typealias, my working name is @unique, but there's probably a much 
>>>> better name for it. When applied to a type-alias it indicates to the 
>>>> type-checker that the type being aliased should be treated as a unique 
>>>> type outside of the scope in which it is declared.
>>> 
>>> I've encountered the same problem in essentially the same place, so I'd 
>>> like to see a solution too.
>>> 
>>> This sounds like a slight variation on what, in previous discussions, has 
>>> been called `newtype`. IIRC, one of the reasons we've never done `newtype` 
>>> is that it's not clear which features you want to bring over from the base 
>>> type, or which types should be used for things like operators. (If you have 
>>> `func + (lhs: Int, rhs: Int) -> Int`, you don't want `func + (lhs: Index, 
>>> rhs: Index) -> Index`; you want `func + (lhs: Index, rhs: Int) -> Index`.)
>>> 
>>> I'd like to suggest a design that I don't think has been considered before. 
>>> Currently, if the first type in an enum's inheritance clause is a concrete 
>>> type, a set of magical behaviors occur:
>>> 
>>> * The enum is conformed to `RawRepresentable` with a `RawValue` of the 
>>> concrete type.
>>> * Each case is associated with a raw value, specified by a literal attached 
>>> to the case.
>>> * `init?(rawValue:)` and `var rawValue { get }` are automatically generated.
>>> 
>>> There is currently no equivalent for structs, but I suggest we add one.
>>> 
>>> If you say:
>>> 
>>>     struct Index: Int {}
>>> 
>>> This is automatically equivalent to saying:
>>> 
>>>     struct Index: RawRepresentable {
>>>             var rawValue: Int
>>>             init(rawValue: Int) { self.rawValue = rawValue }
>>>     }
>>> 
>>> And a special rule is applied: You may not declare any other stored 
>>> properties.
>>> 
>>> Additionally, for both `enum`s and `struct`s with raw types, I would 
>>> suggest that, if you conform to a protocol which the raw type conforms to 
>>> and then fail to fulfill its (non-defaulted) requirements, Swift should 
>>> generate a member which forwards to the raw value's implementation. It 
>>> might even be nice to do the same when an initializer, method, property, or 
>>> subscript is declared without providing a body. This would make it easy to 
>>> decide which functionality should be exposed and how it should be 
>>> provided--and it would provide a partial way to fulfill the frequent 
>>> request for syntactic sugar for `Equatable`, `Hashable`, and `Comparable` 
>>> conformances. (I could imagine this being generalized later on.)
>>> 
>>> The main drawback I can see is that the `rawValue` could not be 
>>> encapsulated, since the conformance to the public `RawRepresentable` 
>>> protocol could not be made private. That might be acceptable in a 
>>> convenience feature, or we might decide (perhaps for both `struct`s and 
>>> `enum`s) that Swift should generate the members without actually conforming 
>>> the type unless explicitly asked to.
>> 
>> A lot of this is very similar to the protocol-based forwarding proposal I 
>> worked on last year.  That proposal would avoid the problems you describe 
>> around not being able to properly encapsulate `RawRepresentable`.  It was 
>> also able to handle many nuances around forwarding of self and associated 
>> type requirements.  It even had an example of how something like `newtype` 
>> could be defined in terms of the mechanisms it provides.
>> 
>> I was mid-way through a second draft when it became clear it was not in 
>> scope for Swift 3.  At that point I deferred further work until the time is 
>> right.  I would like to revisit it eventually, but it is clearly out of 
>> scope for Swift 4 as well.
> 
> Did you get as far as putting up anywhere to look at?
> 
> It may be relevant to Swift 4 stage 2, though I'll admit I'm confused as hell 
> what is and is not in scope; but I believe the ABI compatibility stuff has 
> been pushed back so it might be accepting more general proposals again, I was 
> going to re-submit some of mine that were out-of-scope before.

No, it’s in a kind of mid-draft state.  I’ll try to get it into a reasonable 
place and post a link sometime soon, but I don’t plan to officially propose it 
unless there is a lot of support, especially from the core team.  This feels 
like something that is probably out of scope so I don’t want to invest too much 
time into it right now unless that proves to be wrong.

> 

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to