Are you sure it works with user-defined struct types? I tried the following code, and got the same error:
protocol MyProtocol {}
struct Blah : MyProtocol { }
func foo() -> [MyProtocol] {
let a = [Blah(), Blah()] as [Blah]
return a
}
'class Blah' works fine.
Even so, this is not the behavior I would have expected. Perhaps someone else can explain why [T] can't be upcasted to [P] when T is a struct and T : P.
Best,
Austin
···
On Jan 25, 2016, at 7:36 PM, Ryan Walklin via swift-users <swift-users@swift.org> wrote:
Hi All,
I have a function which returns a closure, which then returns an array of objects conforming to a protocol.
I'm reasonably sure Arrays and other collections are covariant, but any user-defined generic type is invariant. This came up in the discussion about making all generics covariant by default.
func foo() -> [MyProtocol] {
let a = [Float(1), Float(2)] as [MyProtocol]
return a
}
but this doesn't (with or without the cast):
func foo() -> [MyProtocol] {
let a = [Float(1), Float(2)] //as [Float]
return a as [MyProtocol]
}
Nor does this:
func foo() -> [MyProtocol] {
let a = [Float(1), Float(2)] as [Float]
let b = a as [MyProtocol]
return b
}
This definitely looks like a bug, or at least something that needs a better compiler error message. (I'm running this in an OS X Xcode project with Swift 2.1, but it doesn't work with Swift 2.2 either.)
Best,
Austin
···
On Jan 25, 2016, at 7:51 PM, Trent Nadeau <tanadeau@gmail.com> wrote:
I think arrays along with other generics are invariant.
On Mon, Jan 25, 2016 at 10:50 PM, Trent Nadeau <tanadeau@gmail.com <mailto:tanadeau@gmail.com>> wrote:
That code works fine for me if I change the cast to "as [MyProtocol]".
protocol MyProtocol {}
struct Blah : MyProtocol { }
func foo() -> [MyProtocol] {
let a = [Blah(), Blah()] as [MyProtocol]
return a
}
On Mon, Jan 25, 2016 at 10:47 PM, Austin Zheng via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Hi Ryan,
Are you sure it works with user-defined struct types? I tried the following code, and got the same error:
protocol MyProtocol {}
struct Blah : MyProtocol { }
func foo() -> [MyProtocol] {
let a = [Blah(), Blah()] as [Blah]
return a
}
'class Blah' works fine.
Even so, this is not the behavior I would have expected. Perhaps someone else can explain why [T] can't be upcasted to [P] when T is a struct and T : P.
Best,
Austin
On Jan 25, 2016, at 7:36 PM, Ryan Walklin via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Hi All,
I have a function which returns a closure, which then returns an array of objects conforming to a protocol.
That code works fine for me if I change the cast to "as [MyProtocol]".
protocol MyProtocol {}
struct Blah : MyProtocol { }
func foo() -> [MyProtocol] {
let a = [Blah(), Blah()] as [MyProtocol]
return a
}
···
On Mon, Jan 25, 2016 at 10:47 PM, Austin Zheng via swift-users < swift-users@swift.org> wrote:
Hi Ryan,
Are you sure it works with user-defined struct types? I tried the
following code, and got the same error:
protocol MyProtocol {}
struct Blah : MyProtocol { }
func foo() -> [MyProtocol] {
let a = [Blah(), Blah()] as [Blah]
return a
}
'class Blah' works fine.
Even so, this is not the behavior I would have expected. Perhaps someone
else can explain why [T] can't be upcasted to [P] when T is a struct and T
: P.
Best,
Austin
On Jan 25, 2016, at 7:36 PM, Ryan Walklin via swift-users < > swift-users@swift.org> wrote:
Hi All,
I have a function which returns a closure, which then returns an array of
objects conforming to a protocol.
I think arrays along with other generics are invariant.
···
On Mon, Jan 25, 2016 at 10:50 PM, Trent Nadeau <tanadeau@gmail.com> wrote:
That code works fine for me if I change the cast to "as [MyProtocol]".
protocol MyProtocol {}
struct Blah : MyProtocol { }
func foo() -> [MyProtocol] {
let a = [Blah(), Blah()] as [MyProtocol]
return a
}
On Mon, Jan 25, 2016 at 10:47 PM, Austin Zheng via swift-users < > swift-users@swift.org> wrote:
Hi Ryan,
Are you sure it works with user-defined struct types? I tried the
following code, and got the same error:
protocol MyProtocol {}
struct Blah : MyProtocol { }
func foo() -> [MyProtocol] {
let a = [Blah(), Blah()] as [Blah]
return a
}
'class Blah' works fine.
Even so, this is not the behavior I would have expected. Perhaps someone
else can explain why [T] can't be upcasted to [P] when T is a struct and T
: P.
Best,
Austin
On Jan 25, 2016, at 7:36 PM, Ryan Walklin via swift-users < >> swift-users@swift.org> wrote:
Hi All,
I have a function which returns a closure, which then returns an array of
objects conforming to a protocol.
The foo pattern fails, but the foo2 pattern works. My existing code with struct type was all of type foo2, so I didn’t appreciate the error. As you stay, still seems like a problem with type inference.
Ryan
···
On 26 Jan 2016, at 2:47 PM, Austin Zheng <austinzheng@gmail.com> wrote:
Hi Ryan,
Are you sure it works with user-defined struct types? I tried the following code, and got the same error:
protocol MyProtocol {}
struct Blah : MyProtocol { }
func foo() -> [MyProtocol] {
let a = [Blah(), Blah()] as [Blah]
return a
}
'class Blah' works fine.
Even so, this is not the behavior I would have expected. Perhaps someone else can explain why [T] can't be upcasted to [P] when T is a struct and T : P.
Best,
Austin
On Jan 25, 2016, at 7:36 PM, Ryan Walklin via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Hi All,
I have a function which returns a closure, which then returns an array of objects conforming to a protocol.
The problem is that an array of protocols is stored using a different representation from an array of plain structs (or classes, for that matter). Converting from [Float] to [MyProtocol] is therefore an O(N) operation, while a normal upcast between class types is O(1) (by sharing the underlying storage).
This does keep tripping people up, though, so maybe an explicit "as" should be considered good enough. The typical workarounds are either to use "as [MyProtocol]" to begin with (as Trent mentioned) or to use 'map' to build a new array ("return a.map { $0 }").
The foo pattern fails, but the foo2 pattern works. My existing code with struct type was all of type foo2, so I didn’t appreciate the error. As you stay, still seems like a problem with type inference.
Ryan
On 26 Jan 2016, at 2:47 PM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:
Hi Ryan,
Are you sure it works with user-defined struct types? I tried the following code, and got the same error:
protocol MyProtocol {}
struct Blah : MyProtocol { }
func foo() -> [MyProtocol] {
let a = [Blah(), Blah()] as [Blah]
return a
}
'class Blah' works fine.
Even so, this is not the behavior I would have expected. Perhaps someone else can explain why [T] can't be upcasted to [P] when T is a struct and T : P.
Best,
Austin
On Jan 25, 2016, at 7:36 PM, Ryan Walklin via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Hi All,
I have a function which returns a closure, which then returns an array of objects conforming to a protocol.
Thanks for your reply. I’ve since discovered the differences in memory representation that you mention, and the performance implications of the conversion.
I’ve worked around this by just using a typed array, as the eventual destination for the array is a Metal buffer via memcpy, so I need a contiguous array.
Regards,
Ryan
···
On 27 Jan 2016, at 5:56 AM, Jordan Rose <jordan_rose@apple.com> wrote:
The problem is that an array of protocols is stored using a different representation from an array of plain structs (or classes, for that matter). Converting from [Float] to [MyProtocol] is therefore an O(N) operation, while a normal upcast between class types is O(1) (by sharing the underlying storage).
This does keep tripping people up, though, so maybe an explicit "as" should be considered good enough. The typical workarounds are either to use "as [MyProtocol]" to begin with (as Trent mentioned) or to use 'map' to build a new array ("return a.map { $0 }").
The foo pattern fails, but the foo2 pattern works. My existing code with struct type was all of type foo2, so I didn’t appreciate the error. As you stay, still seems like a problem with type inference.
Ryan
On 26 Jan 2016, at 2:47 PM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:
Hi Ryan,
Are you sure it works with user-defined struct types? I tried the following code, and got the same error:
protocol MyProtocol {}
struct Blah : MyProtocol { }
func foo() -> [MyProtocol] {
let a = [Blah(), Blah()] as [Blah]
return a
}
'class Blah' works fine.
Even so, this is not the behavior I would have expected. Perhaps someone else can explain why [T] can't be upcasted to [P] when T is a struct and T : P.
Best,
Austin
On Jan 25, 2016, at 7:36 PM, Ryan Walklin via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Hi All,
I have a function which returns a closure, which then returns an array of objects conforming to a protocol.