Generic requirement that Some: AsyncSequence is not throwing - swift

I would like to extend AsyncSequence in ways that depend on whether the sequence can throw. Neither AsyncSequence nor AsyncIteratorProtocol distinguish such sequences explicitly. Yet, the concurrency module does come with concrete sequences with throwing and non-throwing variants. The only generic difference I see is that the next method of non-throwing sequences are rethrowing. Here is an example:
extension AsyncMapSequence : AsyncSequence {
struct Iterator : AsyncIteratorProtocol {
mutating func next() async rethrows -> Transformed?
}
}
Whereas the throwing variant is a plain throws:
extension AsyncThrowingMapSequence : AsyncSequence {
struct Iterator : AsyncIteratorProtocol {
mutating func next() async throws -> Transformed?
}
}
(I am not even sure how rethrows is even possible for a method that does not take any arguments. The only thing that comes to mind is that the curried expression of such a method could throw some light on that...)
So, the question is how to express something along the lines of:
extension AsyncSequence where AsyncIterator /* is not throwing */ {
}

When this proposal is fully implemented you will be able to express conformance to a failable sequence by providing some syntax sugar
extension AsyncSequence where nothrow AsyncIterator {
or
struct Foo<S: nothrow AsyncSequence>
This comes from the #rethrows annotation currently attached to AsyncSequence
#rethrows public protocol AsyncSequence

Related

Swift Protocol inheriting Protocol method with same name

While reading swift forum about exceptions I found interesting issue. One of the examples about exceptions was something like this:
protocol Base {
func foo() throws -> Int
}
protocol Refined: Base {
func foo() -> Int
}
struct Test: Refined {
func foo() -> Int {
0
}
}
It's interesting, I thought it was typo that it would not compile, but it does. I am not sure how this does work behind the scenes. I mean when protocol adopts another protocol it adopts also its requirements. But in this case declaring same method without throws somehow satisfies also first protocol Base.
At the very least I expected Test to need to have 2 implementations of foo. What am I missing here?
This is because a non-throwing function is by definition a sub-type of a throwing function
From the Swift Programming Language book
The throws keyword is part of a function’s type, and nonthrowing functions are subtypes of throwing functions. As a result, you can use a nonthrowing function in the same places as a throwing one.
But you can't do it the other way around so the below code will generate an error
protocol Base {
func foo() -> Int
}
protocol Refined: Base {
func foo() throws -> Int //error: Cannot override non-throwing method with throwing method
}
Also note that this is not only for protocols, if you remove the func declaration from Refined you can still implement the function in Test as non throwing.

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)

What is "Element" type?

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.

Swift function in class definition can't found another global function with similar name but different parameters [duplicate]

After converting from Swift 2.2 to 3.0 my Array extension does not compile anymore, because it contains a call to global standard library function min<T>(T,T) and shows compiler error extra argument in call.
Here's a simple way to reproduce the error:
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
return min(first, second) // compiler error: "Extra argument in call"
}
}
I get the same error when adding the same function to an extension of Dictionary, while the exact same code compiles just fine in an extension of other types (e.g. String or AudioBuffer):
Looking at the documentation of Array and Dictionary, I find that there are instance methods on Sequence named public func min() -> Element? and public func min(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?. While both String and AudioBuffer do not have any kind of min(...) function.
Is it possible that this is the reason why I can't call the global function? The compiler can't distinguish between global func min<T>(T,T) and self.min(...) although they have completely different signatures?
Is this a bug or a feature? What am I doing wrong? How can I call min(T,T) correctly inside an Array extension?
I see no reason why the compiler shouldn't be able to resolve this function call, therefore I would consider it a bug (it has already been filed – see SR-2450).
It seems to occur whenever attempting to call a top-level function with the same name, but unambiguously different signature to a method or property that's accessible from the same scope in a given type (instance or static).
An even simpler example would be:
func foo(_ a: Int) {}
struct Foo {
func foo() {} // or static func foo() {}, var foo = 0, static var foo = 0
func bar() {
foo(2) // error: argument passed to call that takes no arguments
}
}
Until fixed, a simple solution would be to prefix the call with the name of the module in which it resides in order to disambiguate that you're referring to the top-level function, rather than the instance one. For the standard library, that's Swift:
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
return Swift.min(first, second)
}
}
In Swift 4, the compiler has a better diagnostic for this error (though the fact that it's still an error is a bug IMO):
extension Array {
func smallestInt(first: Int, second: Int) -> Int {
// Use of 'min' refers to instance method 'min(by:)'
// rather than global function 'min' in module 'Swift'
// - Use 'Swift.' to reference the global function in module 'Swift'
return min(first, second)
}
}
Although what's interesting is that the compiler will now also warn on attempting to call a standard library method with the same name as a stdlib top-level function:
extension Array where Element : Comparable {
func smallest() -> Element? {
// Use of 'min' treated as a reference to instance method in protocol 'Sequence'
// - Use 'self.' to silence this warning
// - Use 'Swift.' to reference the global function
return min()
}
}
In this case, as the warning says, you can silence it by using an explicit self.:
extension Array where Element : Comparable {
func smallest() -> Element? {
return self.min()
}
}
Although what's really curious about this warning is it doesn't appear to extend to non-stdlib defined functions:
func foo(_ a: Int) {}
struct Foo {
func foo() {}
func bar() {
foo() // no warning...
}
}

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
}