What is "Element" type? - swift

Reading Swift Programming Language book I've seen number of references to type Element, which is used to define type of collection items. However, I can't find any documentation on it, is it class, protocol? What kind of functionality/methods/properties it has?
struct Stack<Element>: Container {
// original Stack<Element> implementation
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
...

If we tried trace the idea of how we do even get Element when working with collections, we would notice that it is related to the Iterator protocol. Let's make it more clear:
Swift Collection types (Array, Dictionary and Set) are all conforms to Collection protocol. Therefore, when it comes to the Collection protocol, we can see that the root of it is the Sequence protocol:
A type that provides sequential, iterated access to its elements.
Sequence has an Element and Iterator associated types, declared as:
associatedtype Element
associatedtype Iterator : IteratorProtocol where Iterator.Element == Element
You could review it on the Sequence source code.
As shown, Iterator also has an Element associated type, which is compared with the sequence Element, well what does that means?
IteratorProtocol is the one which does the actual work:
The IteratorProtocol protocol is tightly linked with the Sequence
protocol. Sequences provide access to their elements by creating an
iterator, which keeps track of its iteration process and returns one
element at a time as it advances through the sequence.
So, Element would be the type of returned element to the sequence.
Coding:
To make it simple to be understandable, you could implement such a code for simulating the case:
protocol MyProtocol {
associatedtype MyElement
}
extension MyProtocol where MyElement == String {
func sayHello() {
print("Hello")
}
}
struct MyStruct: MyProtocol {
typealias MyElement = String
}
MyStruct().sayHello()
Note that -as shown above- implementing an extension to MyProtocol makes MyElement associated type to be sensible for the where-clause.
Therefore sayHello() method would be only available for MyProtocol types (MyStruct in our case) that assign String to MyElement, means that if MyStruct has been implemented as:
struct MyStruct: MyProtocol {
typealias MyElement = Int
}
you would be not able to:
MyStruct().sayHello()
You should see a compile-time error:
'MyStruct.MyElement' (aka 'Int') is not convertible to 'String'
The same logic when it comes to Swift collection types:
extension Array where Element == String {
func sayHello() {
print("Hello")
}
}

Here is the definition in the Apple documentation
Element defines a placeholder name for a type to be provided later.
This future type can be referred to as Element anywhere within the
structure’s definition.

Element is usually used as the generic type name for collections, as in
public struct Array<Element> { ... }
so it is what you construct your array from, and not something predefined by the language.

Element is a purpose-built (and defined) placeholder for structures. Unlike some of the answers/comments have suggested, Element cannot always be substituted for T because T without the proper context is undefined. For example, the following would not compile:
infix operator ++
extension Array {
static func ++ (left: Array<T>, right: T) -> Array {
...
}
}
The compiler doesn't know what T is, it's just an arbitrary letter—it could be any letter, or even symbol (T has just become Swift convention). However, this will compile:
infix operator ++
extension Array {
static func ++ (left: Array<Element>, right: Element) -> Array {
...
}
}
And it compiles because the compiler knows what Element is, a defined placeholder, not a type that was arbitrarily made up.

Related

Swift Implementation generic function

I'm a developer on Java and I'm trying to write in Swift the same solution that I have in Java code.
Is it possible to do this on Swift?
Example Java:
public interface Converter<S,T> {
T convert(S in)
}
public class CarConverterToDTO implements Converter<Car, CarDTO> {
#Override
public CarDTO convert(Car in) {
.....
}
}
Example Swift:
protocol Converter {
func convert<IN, OUT>(in: IN) -> OUT
}
How it would be the implementation?
Thanks!!!
What appears to be a simple question is actually the tip of a rather large and unpleasant iceberg…
I'm going to start by giving you what is probably the real solution to your problem:
class Converter<Input, Output> {
func convert(_ input: Input) -> Output {
fatalError("subclass responsibility")
}
}
struct Car { }
struct CarDTO { }
class DTOCarConverter: Converter<Car, CarDTO> {
override func convert(_ input: Car) -> CarDTO {
return CarDTO()
}
}
Above, I've translated your Java Converter interface into a Swift class instead of a Swift protocol. That's probably what you want.
Now I'll explain why.
A programmer coming from Java to Swift might think that a Swift protocol is the equivalent of a Java interface. So you might write this:
protocol Converter {
associatedtype Input
associatedtype Output
func convert(_ input: Input) -> Output
}
struct Car { }
struct CarDTO { }
class /* or struct */ DTOCarConverter: Converter {
func convert(_ input: Car) -> CarDTO {
return CarDTO()
}
}
Okay, now you can create a converter and convert something:
let converter = DTOCarConverter()
let car = Car()
let dto = converter.convert(car)
But you're going to run into a problem as soon as you want to write a function that takes a Converter as an argument:
func useConverter(_ converter: Converter) { }
// ^
// error: protocol 'Converter' can only be used as a generic constraint because it has Self or associated type requirements
“Well, duh,” you say, “you forgot the type arguments!” But no, I didn't. Swift doesn't allow explicit type arguments after a protocol name:
func useConverter(_ converter: Converter<Car, CarDTO>) { }
// ^ ~~~~~~~~~~~~~
// error: cannot specialize non-generic type 'Converter'
I don't want to get into why you can't do this. Just accept that a Swift protocol is not generally equivalent to a Java interface.
A Swift protocol with no associated types and no mention of Self is, generally, equivalent to a non-generic Java interface. But a Swift protocol with associated types (or that mentions Self) is not really equivalent to any Java construct.
When discussing this problem, we often use the acronym “PAT”, which stands for “Protocol with Associated Types” (and includes protocols that mention Self). A PAT doesn't define a type that you can use as a function argument, return value, or property value. There's not much you can do with a PAT:
You can define a subprotocol. For example, Equatable is a PAT because it defines the == operator to take two arguments of type Self. Hashable is a subprotocol of Equatable.
You can use a PAT as a type constraint. For example, Set is a generic type. Set's type parameter is named Element. Set constrains its Element to be Hashable.
So you can't write a function that takes a plain Converter as an argument. But you can write a function that takes any implementation of Converter as an argument, by making the function generic:
func useConverter<MyConverter: Converter>(_ converter: MyConverter)
where MyConverter.Input == Car, MyConverter.Output == CarDTO
{ }
That compiles just fine. But sometimes it's inconvenient to make your function generic.
And there's another problem that this doesn't solve. You might want a container that holds various Converters from Car to CarDTO. That is, you might want something like this:
var converters: [Converter<Car, CarDTO>] = []
// ^ ~~~~~~~~~~~~~
// error: cannot specialize non-generic type 'Converter'
We can't fix this by making converters generic, like we did with the useConverter function.
What you end up needing is a “type-erased wrapper”. Note that “type-erased” here has a different meaning that Java's “type erasure”. In fact it's almost the opposite of Java's type erasure. Let me explain.
If you look in the Swift standard library, you'll find types whose names start with Any, like AnyCollection. These are mostly “type-erased wrappers” for PATs. An AnyCollection conforms to Collection (which is a PAT), and wraps any type that conforms to Collection. For example:
var carArray = Array<Car>()
let carDictionary = Dictionary<String, Car>()
let carValues = carDictionary.values
// carValues has type Dictionary<String, Car>.Values, which is not an array but conforms to Collection
// This doesn't compile:
carArray = carValues
// ^~~~~~~~~
// error: cannot assign value of type 'Dictionary<String, Car>.Values' to type '[Car]'
// But we can wrap both carArray and carValues in AnyCollection:
var anyCars: AnyCollection<Car> = AnyCollection(carArray)
anyCars = AnyCollection(carValues)
Note that we have to explicitly wrap our other collections in AnyCollection. The wrapping is not automatic.
Here's why I say this is almost the opposite of Java's type erasure:
Java preserves the generic type but erases the type parameter. A java.util.ArrayList<Car> in your source code turns into a java.util.ArrayList<_> at runtime, and a java.util.ArrayList<Truck> also becomes a java.util.ArrayList<_> at runtime. In both cases, we preserve the container type (ArrayList) but erase the element type (Car or Truck).
The Swift type-erasing wrapper erases the generic type but preserves the type parameter. We turn an Array<Car> into an AnyCollection<Car>. We also turn a Dictionary<String, Car>.Values into an AnyCollection<Car>. In both cases, we lose the original container type (Array or Dictionary.Values) but preserve the element type (Car).
So anyway, for your Converter type, one solution to storing Converters in a container is to write an AnyConverter type-erased wrapper. For example:
struct AnyConverter<Input, Output>: Converter {
init<Wrapped: Converter>(_ wrapped: Wrapped) where Wrapped.Input == Input, Wrapped.Output == Output {
self.convertFunction = { wrapped.convert($0) }
}
func convert(_ input: Input) -> Output { return convertFunction(input) }
private let convertFunction: (Input) -> Output
}
(There are multiple ways to implement type-erased wrappers. That is just one way.)
You can then use AnyConverter in property types and function arguments, like this:
var converters: [AnyConverter<Car, CarDTO>] = [AnyConverter(converter)]
func useConverters(_ converters: [AnyConverter<Car, CarDTO>]) {
let car = Car()
for c in converters {
print("dto = \(c.convert(car))")
}
}
But now you should ask: what's the point? Why bother making Converter a protocol at all, if I'm going to have to use a type-erased wrapper? Why not just use a base class to define the interface, with subclasses implementing it? Or a struct with some closures provided at initialization (like the AnyConverter example above)?
Sometimes, there's not a good reason to use a protocol, and it's more sensible to just use a class hierarchy or a struct. So you should take a good look at how you're implementing and using your Converter type and see if a non-protocol approach is simpler. If it is, try a design like I showed at the top of this answer: a base class defining the interface, and subclasses implementing it.
The Swift equivalent to your Java code looks like this.
protocol Converter {
associatedtype Input
associatedtype Output
func convert(input: Input) -> Output
}
class CarConverterToDTO: Converter {
typealias Input = Car
typealias Output = CarDTO
func convert(input: Car) -> CarDTO {
return CarDTO()
}
}
Explanation
The equivalent to a generic Java interface in Swift, would be a protocol with associatedtypes.
protocol Converter {
associatedtype Input
associatedtype Output
}
To create an implementation of that protocol, the implementation must specify which types the associated types maps to, using typealias.
class CarConverterToDTO: Converter {
typealias Input = Car
typealias Output = CarDTO
}
Type Erasure
If you try to use to this approach, you may run into the issue of trying to store an instance of your generic protocol in a variable or property, in which case you will get the compiler error:
protocol 'Converter' can only be used as a generic constraint because it has Self or associated type requirements
The way to solve this issue in Swift, is by using type erasure, where you create a new implementation of your generic protocol, that itself is a generic type (struct or class), and uses a constructor accepting a generic argument, matching your protocol, like so:
struct AnyConverter<Input, Output>: Converter {
// We don't need to specify type aliases for associated types, when the type
// itself has generic parameters, whose name matches the associated types.
/// A reference to the `convert(input:)` method of a converter.
private let _convert: (Input) -> Output
init<C>(_ converter: C) where C: Converter, C.Input == Input, C.Output == Output {
self._convert = converter.convert(input:)
}
func convert(input: Input) -> Output {
return self._convert(input)
}
}
This is usually accompanied by an extension function on the generic protocol, that performs the type erasure by creating an instance of AnyConverter<Input, Output> using self, like so:
extension Converter {
func asConverter() -> AnyConverter<Input, Output> {
return AnyConverter(self)
}
}
Using type erasure, you can now create code that accepts a generic Converter (by using AnyConverter<Input, Output>), that maps Car to CarDTO:
let car: Car = ...
let converter: AnyConverter<Car, CarDTO> = ...
let dto: CarDTO = converter.convert(input: car)

More than one protocol in a type constraint

I want to use a generic typed class and a type constraint:
class MyCustomClass<T : Equatable> {
var a: Array<T>
init() {
a = Array<T>()
}
}
That works fine. But what happens if I want to use a second protocol, f.e.
class MyCustomClass<T : Equatable, IndexableBase> {
var a: Array<T>
init() {
a = Array<T>()
}
}
It says that the initializer fails because I have to use 2 instead of 1 argument. That I don't understand.
Swift 3
(I've replaced IndexableBase with Collection in your example, you should prefer the latter)
As per Swift 3, protocol composition use the infix operator & over the previous protocol<...> construct, as described in the accepted and implemented evolution proposal:
SE-0095: Replace protocol<P1,P2> syntax with P1 & P2 syntax
Hence, using protocol composition you may place the combined type constraint at the T placeholder in the parameter list:
class MyCustomClass<T: Equatable & Collection> { /* ... */ }
As an alternative to protocol composition, you could also make use of where clause to join several type (and subtype) constraint. As per the accepted and implemented evolution proposal:
Se-0081: Move where clause to end of declaration
the where clause has been moved to end of the declaration, in which case your example would read:
class MyCustomClass<T: Equatable> where T: Comparable { /* ... */ }
or, even place the full protocol composition with the where clause at the end of the declaration
class MyCustomClass<T> where T: Equatable & Comparable { /* ... */ }
What style should we prefer?
The interesting discussion is what we should consider "best practice", as this particular subject is not specified Swift API guidelines. Do we place
all (main type) constraints in the parameter list, or
all constraints at the end of the declaration, or
split up constraints with some in the parameter list and others placed at the end of the declaration?
Consider the following contrived example, where we have a construct a protocol that we plan to use as a type constraint (Doable), which in itself holds an associatedtype to which we may place a type constraint.
protocol Doable {
associatedtype U
}
Using the different methods above, all the following three alternatives are valid, syntactically
// alternative #1
func foo<T: Equatable & Doable>(_ bar: T) -> () where T.U: Comparable { /* ... */ }
// alternative #2
func foo<T: Equatable>(_ bar: T) -> () where T: Doable, T.U: Comparable { /* ... */ }
// alternative #3
func foo<T>(_ bar: T) -> () where T: Equatable & Doable, T.U: Comparable { /* ... */ }
I'll quote Apple dev Joe Groff from the evolution thread that that brought forth SE-0081:
It's a judgment call. It's my feeling that in many cases, a generic
parameter is constrained by at least one important protocol or base
class that's worth calling out up front, so it's reasonable to allow
things like
func foo<C: Collection>(x: C) -> C.Element
without banishing the Collection constraint too far from the front
of the declaration.
So in the contrived example above, it might be appropriate to use protocol composition for the type constraints that apply directly to the generic placeholder T, and place these constraints in the parameter list, whereas the subtype constraint of T.U is placed at the end of the declaration. Namely, alternative #1 above.
you can use this workaround
class MyCustomClass<T: Equatable where T: IndexableBase > {
var a: Array<T>
init() {
a = Array<T>()
}
}
Swift 4:
class MyCustomClass<T: Equatable> where T: Collection {
var a: Array<T>
init() {
a = Array<T>()
}
}

Swift: Any Kind of sequence as a function parameter

I have created my custom sequence type and I want the function to accept any kind of sequence as a parameter. (I want to use both sets, and my sequence types on it)
Something like this:
private func _addToCurrentTileset(tilesToAdd tiles: SequenceType)
Is there any way how I can do it?
It seems relatively straightforward, but I can't figure it out somehow. Swift toolchain tells me:
Protocol 'SequenceType' can only be used as a generic constraint because it has Self or associated type requirements, and I don't know how to create a protocol that will conform to SequenceType and the Self requirement from it.
I can eliminate the associatedType requirement with, but not Self:
protocol EnumerableTileSequence: SequenceType {
associatedtype GeneratorType = geoBingAnCore.Generator
associatedtype SubSequence: SequenceType = EnumerableTileSequence
}
Now if say I can eliminate self requirement, then already with such protocol definition other collectionType entities like arrays, sets won't conform to it.
Reference:
my custom sequences are all subclasses of enumerator type defined as:
public class Enumerator<T> {
public func nextObject() -> T? {
RequiresConcreteImplementation()
}
}
extension Enumerator {
public var allObjects: [T] {
return Array(self)
}
}
extension Enumerator: SequenceType {
public func generate() -> Generator<T> {
return Generator(enumerator: self)
}
}
public struct Generator<T>: GeneratorType {
let enumerator: Enumerator<T>
public mutating func next() -> T? {
return enumerator.nextObject()
}
}
The compiler is telling you the answer: "Protocol 'Sequence' can only be used as a generic constraint because it has Self or associated type requirements".
You can therefore do this with generics:
private func _addToCurrentTileset<T: Sequence>(tilesToAdd tiles: T) {
...
}
This will allow you to pass in any concrete type that conforms to Sequence into your function. Swift will infer the concrete type, allowing you to pass the sequence around without lose type information.
If you want to restrict the type of the element in the sequence to a given protocol, you can do:
private func _addToCurrentTileset<T: Sequence>(tilesToAdd tiles: T) where T.Element: SomeProtocol {
...
}
Or to a concrete type:
private func _addToCurrentTileset<T: Sequence>(tilesToAdd tiles: T) where T.Element == SomeConcreteType {
...
}
If you don't care about the concrete type of the sequence itself (useful for mixing them together and in most cases storing them), then Anton's answer has got you covered with the type-erased version of Sequence.
You can use type-eraser AnySequence for that:
A type-erased sequence.
Forwards operations to an arbitrary underlying sequence having the same Element type, hiding the specifics of the underlying SequenceType.
E.g. if you will need to store tiles as an internal property or somehow use its concrete type in the structure of you object then that would be the way to go.
If you simply need to be able to use the sequence w/o having to store it (e.g. just map on it), then you can simply use generics (like #originaluser2 suggests). E.g. you might end up with something like:
private func _addToCurrentTileset<S: SequenceType where S.Generator.Element == Tile>(tilesToAdd tiles: S) {
let typeErasedSequence = AnySequence(tiles) // Type == AnySequence<Tile>
let originalSequence = tiles // Type == whatever type that conforms to SequenceType and has Tile as its Generator.Element
}

Defining typeliases declared in other protocols

I'm creating a protocol that extends from CollectionType, however, I'm introducing new typealiases that eliminate the need for Element in CollectionType (or rather, they allow me to compute it).
I'll use a simple MapType protocol as an example:
protocol MapType : CollectionType, DictionaryLiteralConvertible {
typealias Key
typealias Value
func updateValue(theNewValue:Value, forKey theKey:Key) -> Value?
}
In the above example, what I really need to be able to do is redefine Element to be the tuple (Key, Value), but I'm not sure how to do this in a protocol rather than a structure or class.
Simply adding typealias Element = (Key, Value) produces no errors, but also doesn't appear to actually do anything within the context of the protocol, for example, the following won't work:
extension MapType {
var firstKey:Key? { return self.generate().next()?.0 }
}
This produces an error, as the generator isn't recognised as returning a tuple (i.e- it has no member .0).
What is the best way to define Element as (Key, Value) in this case, such that I can use it within protocol extensions? Is this even possible?
We can't necessarily force that the Element type inherited from the CollectionType protocol is necessarily a tuple made up of the Key and Value types from the MapType.
However, we can limit our protocol extension to only add the firstKey method to those that do conform to the protocols in such a way using a where statement.
Consider this simplified example:
protocol Base {
typealias Element
func first() -> Element?
}
protocol Child: Base {
typealias Key
typealias Value
func last() -> (Key, Value)?
}
extension Child where Self.Element == (Self.Key, Self.Value) {
var firstKey:Key? { return self.first()?.0 }
}
struct ChildStruct: Child {
func first() -> (String, Int)? {
return ("Foo", 1)
}
func last() -> (String, Int)? {
return ("Bar", 2)
}
}
let c = ChildStruct()
let first = c.first()
let firstKey = c.firstKey
You're basically trying to create a where clause inside of a protocol. That's not possible in Swift today. You can not constrain associated types based on other associated types. Someday maybe, but not today.
You'll need to rethink how you're attacking the problem. The likely solution is to use a generic struct rather than a protocol (otherwise you tend to wind up with a lot of duplicated where clauses all over your code). You can see this recent dotSwift talk for more detailed examples.

Self in protocol

I am learning swift and playing with Xcode.
and I always dig into the definitions. I have seen that:
public protocol GeneratorType {
typealias Element
#warn_unused_result
public mutating func next() -> Self.Element?
}
A struct that conforming this protocol:
public struct IndexingGenerator<Elements : Indexable> : GeneratorType, SequenceType {
public init(_ elements: Elements)
public mutating func next() -> Elements._Element?
}
I know 'Self' means that returning the conforming type. But what does 'Self.Element' mean?
and the function that implemented the requirement that returning 'Elements._Element?', I can’t see 'Elements._Element?' is equal to 'Self.Element?'.
Can anyone explain to me this?
and tell me more about this. thank you.
Self.Element refers to the concrete type that any type implementing GeneratorType protocol will declare as its Element typealias.
For example, in this generator of Fibonacci numbers:
struct Fibonacci: GeneratorType {
typealias Element = Int
private var value: Int = 1
private var previous: Int = 0
mutating func next() -> Element? {
let newValue = value + previous
previous = value
value = newValue
return previous
}
}
... you implement GeneratorType protocol and indicate what will be its Element typealias (Int in this case), and that's the type that generator's next() will be returning (well, actually the optional of that type).
Quite often, though, you would not have to explicitly specify typealiases when implementing parametrised protocols, as Swift is smart enough to infer them for you. E.g. for the Fibonacci numbers generator from the above example the following will also do:
struct Fibonacci: GeneratorType {
private var value: Int = 1
private var previous: Int = 0
mutating func next() -> Int? {
let newValue = value + previous
previous = value
value = newValue
return previous
}
}
... Swift knows from the signature of next() that it returns Int?, and that GeneratorType implementors also must have next() in their to-do list, and that these methods must return Element? types. So, Swift just puts 2 and 2 together, and infers that Element? must be the same thing as Int?, and therefore Element == Int.
About this:
public struct IndexingGenerator<Elements : Indexable> : GeneratorType, SequenceType {
public init(_ elements: Elements)
public mutating func next() -> Elements._Element?
}
Here we have four things going on:
We declare generic type IndexingGenerator that takes a parameter-type called Elements.
This Elements type has a constraint that it must implement Indexable protocol.
The generator that we implement is supposed to return values of the type that is accessible via Indexable interface of Elements, which is known to IndexingGenerator via dot-syntax as Elements._Element.
Swift infers that Element of IndexingGenerator is the same thing as Elements._Element.
So, essentially the above delclaration is equivalent to:
public struct IndexingGenerator<Elements : Indexable> : GeneratorType, SequenceType {
public typealias Element = Elements._Element
public init(_ elements: Elements)
public mutating func next() -> Element?
}
Finally, if curious why _Element and not just Element like in GeneratorType, here is what they write in the open-source Swift repository (under swift/stdlib/public/core/Collection.swift):
The declaration of _Element and subscript here is a trick used to break a cyclic conformance/deduction that Swift can't handle. We need something other than a CollectionType.Generator.Element that can be used as IndexingGenerator<T>'s Element. Here we arrange for the CollectionType itself to have an Element type that's deducible from its subscript. Ideally we'd like to constrain this Element to be the same as CollectionType.Generator.Element, but we have no way of expressing it today.