Swift lacks append for arrays of compatible types
| Originator: | jlieske | ||
| Number: | rdar://17226478 | Date Originated: | |
| Status: | Open | Resolved: | |
| Product: | OS X SDK | Product Version: | Xcode6 beta: Version 6.0 (6A215l) |
| Classification: | Enhancement | Reproducible: | Always |
The Swift language supports supports strongly-typed arrays, using the type system and copying semantics to ensure code correctness. At present, there is a gap in functionality when working with type hierarchies.
* There is no “+” operator that allows the creation of arrays from subtypes of a common base class.
* The “+=“ operator does not support appending an array of a compatible subtype, even through the operator supports appending a single element of a subtype.
Using the type hierarchy from the Swift manual:
class MediaItem {
let name: String
init(name: String) {
self.name = name
}
}
class Movie: MediaItem {
let director: String
init(name: String, director: String) {
self.director = director
super.init(name: name)
}
}
class Song: MediaItem {
let artist: String
init(name: String, artist: String) {
self.artist = artist
super.init(name: name)
}
}
These two arrays get the inferred type of Movie[] and Song[] respectively:
let movies = [
Movie(name: "Casablanca", director: "Michael Curtiz"),
Movie(name: "Citizen Kane", director: "Orson Welles")
]
let songs = [
Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
Song(name: "The One And Only", artist: "Chesney Hawkes"),
Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]
However, the following line fails:
let mediaItems: MediaItem[] = movies + songs
/Users/jay/Coding/Swift/TrySwift/TryArray/main.swift:42:38: error: could not find an overload for '+' that accepts the supplied arguments
let mediaItems: MediaItem[] = movies + songs
~~~~~~~^~~~~~~
Trying that with a mutable array instead also fails:
var mediaItems: MediaItem[] = movies
mediaItems += songs
/Users/jay/Coding/Swift/TrySwift/TryArray/main.swift:45:12: error: could not find an overload for '+=' that accepts the supplied arguments
mediaItems += songs
~~~~~~~~~~~^~~~~~~~
The work around is to append the elements individually:
var mediaItems: MediaItem[] = movies
for song in songs { mediaItems += song }
I have tried to define my own append function. However, I have not yet found a way to express the type constraint that “Other” is a subtype of “Dest”. My attempt with the following fails to compile:
func myConcat<Dest,Other where Other : Dest>(var dest: Dest[], other: Other[]) -> Dest[] {
for o in other { dest += o }
return dest
}
/Users/jay/Coding/Swift/TrySwift/TryArray/main.swift:48:26: error: type 'Other' constrained to non-protocol type 'Dest'
func myConcat<Dest,Other where Other : Dest>(var dest: Dest[], other: Other[]) -> Dest[] {
^
In general, I notice that arrays do not behave covariantly. This is sound typing in the face of mutation, but for a read-only operation like append, I would expect covariant behavior.
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!
The issue still exists in OS X SDK 10.10 Beta 3:
main.swift:42:31: error: '[Movie]' is not convertible to 'UInt8' let mediaItems: [MediaItem] = movies + songs ^ main.swift:45:1: error: '[MediaItem]' is not identical to 'UInt8' mediaItems += songs ^