> On Feb 18, 2017, at 2:18 AM, Haravikk via swift-evolution 
> <[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.

-- 
Brent Royal-Gordon
Architechies

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

Reply via email to