[Pre-proposal] Replace [Foo] With CollectionType


(Dave Abrahams) #1

On May 24, 2016, at 9:35 PM

···

on Tue May 24 2016, Matthew Johnson <swift-evolution@swift.org> wrote:

, Austin Zheng
<austinzheng@gmail.com> wrote:

    On Tue, May 24, 2016 at 4:24 PM, Brent Royal-Gordon > <brent@architechies.com> wrote:

    > I’m not sure what you mean about introducing type unsafely.

        What I mean is that once you do this:

        let x: AnyCollection<Character> = myArrayOfCharacters
        let y: AnyCollection<Character> = myString.characters

        Both `x` and `y` have indices of type `Any<Comparable>`, and will now
        accept each others' indices:

        for i in x.indices {
        print(y[i]) // Oops!
        }

        If this rule:

        > The generalized existentials proposal goes out of its way to be
        explicit about the fact that only type safe operations would be visible
        through the existential.

        Is trying to say that this isn't the case because APIs using the
        collection's `Index` are not exposed on an `AnyCollection`, well, then
        I'm not sure what `AnyCollection` is actually supposed to be used for.

    If there's any way that the rules that I've proposed can be relaxed without
    sacrificing type safety, I would love to hear it. I think the difference in
    'power' in this regard between a function that uses generic types and a
    function that uses existentials is something inherent to how each works,
    though.

The primary difference is the freedom to accept an index which is invalid and
call fatalError when you get it. We don't want existentials to do something
that. But with user-defined types we have the flexibility to do that if we
decide it is the right design.

I'm not sure I agree that Existentials shouldn't do that. The amount of
boilerplate one needs to construct a user-defined simulation of an
existential in these cases can be prohibitive. Why shouldn't the
compiler handle it for us?

--
Dave


(Matthew Johnson) #2

On May 24, 2016, at 9:35 PM

, Austin Zheng

I’m not sure what you mean about introducing type unsafely.

       What I mean is that once you do this:

       let x: AnyCollection<Character> = myArrayOfCharacters
       let y: AnyCollection<Character> = myString.characters

       Both `x` and `y` have indices of type `Any<Comparable>`, and will now
       accept each others' indices:

       for i in x.indices {
       print(y[i]) // Oops!
       }

       If this rule:

The generalized existentials proposal goes out of its way to be

       explicit about the fact that only type safe operations would be visible
       through the existential.

       Is trying to say that this isn't the case because APIs using the
       collection's `Index` are not exposed on an `AnyCollection`, well, then
       I'm not sure what `AnyCollection` is actually supposed to be used for.

   If there's any way that the rules that I've proposed can be relaxed without
   sacrificing type safety, I would love to hear it. I think the difference in
   'power' in this regard between a function that uses generic types and a
   function that uses existentials is something inherent to how each works,
   though.

The primary difference is the freedom to accept an index which is invalid and
call fatalError when you get it. We don't want existentials to do something
that. But with user-defined types we have the flexibility to do that if we
decide it is the right design.

I'm not sure I agree that Existentials shouldn't do that. The amount of
boilerplate one needs to construct a user-defined simulation of an
existential in these cases can be prohibitive. Why shouldn't the
compiler handle it for us?

I know it involves a lot of boilerplate that is better avoided and can be prohibitive and steer one away from designs that might otherwise be useful.

But the behavior of AnyCollection (specifically AnyIndex) involves custom logic that decides where and how to introduce the potential for fatalError. I definitely don't want the compiler doing this without an explicit request of some kind. Existentials should at least be safe by default. If we *really* need a way to introduce unsafe existentials it should be opt-in (I have no idea what that might look like). But I'm not sure it's worth introducing a feature like that just to make it easier to create types with an unsafe interface.

But why would you want the unsafe behavior of AnyCollection when we could have a safe 'typealias AnyCollection<T> = Collection where .Element == T'? You would be able to safely use indexes received from the collection to index back into it. Usage that would cause a runtime crash can be caught at compile time. The only thing you wouldn't be able to do is take an index received from one collection and use with another. Is there a specific use case the current design supports that the safer existential would not?

-Matthew

···

Sent from my iPad

On May 27, 2016, at 3:43 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Tue May 24 2016, Matthew Johnson <swift-evolution@swift.org> wrote:

<austinzheng@gmail.com> wrote:
   On Tue, May 24, 2016 at 4:24 PM, Brent Royal-Gordon >> <brent@architechies.com> wrote:

--
Dave

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