Extension to generic struct where element is generic struct - swift

I have a generic structs FutureValue<Element> and Failable<Element>, which both implement map…
struct FutureValue<Element> {
func map<U>(_ t: (Element) -> U) -> FutureValue<U> …
}
struct Failable<Element> {
func map<U>(_ t: (Element) -> U) -> Failable<U> …
}
I'd like to write an extension on FutureValue to specialise it when its Element is any Failable, so that I can implement a map like function that maps on the contained Element in the FutureValue<Failable<Element>>
How can I do this in Swift?

You just need to create a protocol that captures "any Failable" and captures the pieces you want for your algorithm.
protocol AnyFailable {
associatedtype Element
func map<U>(_ t: (Element) -> U) -> Failable<U>
}
And express that all Failables are AnyFailable.
extension Failable: AnyFailable {}
You may want to add methods on the protocol to extract data you need or provide methods.
Then, create your extension:
extension FutureValue where Element: AnyFailable {
func map<U>(_ t: (Element.Element) -> U) -> FutureValue<Failable<U>> {
// You will probably need to provide your own implementation here
return FutureValue<Failable<U>>(element: element.map(t))
}
}
It's worth noting how I constructed this. I started by writing a more concrete form based on String (just to pick a random thing):
extension FutureValue where Element == Failable<String> {
func map<U>(_ t: (String) -> U) -> FutureValue<Failable<U>> {
...
}
}
And I wrote a simple piece of consuming code:
let f = FutureValue(element: Failable(element: "alice"))
print(f.map { $0.first })
And from there, I extracted the pieces I needed into a protocol. This tends to get you moving in the right direction, step by step. It is very challenging sometimes to jump directly to the most generic form.

Many thanks to Rob for his super answer.
The approach I took in the end is slightly different so I'm adding it as a second answer. For the case of an extension to a generic that is constrained on the element being of some kind, I feel this approach is simpler. It's also a readily introduced "pattern" that can be easily dropped in to similar situations.
/*
Protocol for things that can be _concretely_ represented as a `Failable`.
I keep it private so it's just used to constrain the protocol extension
below.
*/
private protocol AsFailable {
associatedtype Element
var asFailable: Failable<Element> {get}
}
/*
`Failable` can definitely be represented `AsFailable`…
*/
extension Failable: AsFailable {
var asFailable: Failable<Element> {
return self
}
}
/*
Use the `AsFailable` protocol to constrain an extension to `FutureValue`
for any `FutureValue` who's `Element` is a `Failable`.
*/
extension FutureValue where Element: AsFailable {
func happyMap<U>(_ t: #escaping (Element.Element) -> U)
-> FutureValue<Failable<U>> {
return map { $0.asFailable.map(t) }
}
}
Rob's approach let me implement map (as set out in the OP), but I started to flounder when I wanted to implement flatMap as well. Switching to the use of AsFailable let me quickly write a simple implementation of flatMap.
I think the AsXXX approach is simper for a case like this where a protocol is just required to act as a constraint.
Here's what happyFlatMap looks like:
func happyFlatMap<U>(_ t: #escaping (FailableElement) -> FutureValue<Failable<U>>)
-> FutureValue<Failable<U>>
{
typealias Out = FutureValue<Failable<U>>
return flatMap {
failable in
switch failable.asFailable {
case let .happy(element):
return t(element)
case let .error(error):
return Out(Failable<U>.error(error))
case let .canceled(reason):
return Out(Failable<U>.canceled(reason))
}
}
}

Related

Swift generic constraint on method does not behave as expected when called from instance

Here is the following piece of Swift code:
class HTTP {
func run<T: Decodable>(handler: (Result<T, Error>) -> Void) {
HTTP.handle(handler: handler)
}
}
extension HTTP {
static func handle<T: Decodable>(handler: (Result<T, Error>) -> Void) {
Swift.print("Base")
}
}
extension HTTP {
static func handle<T: Decodable & Offline>(handler: (Result<T, Error>) -> Void) {
Swift.print("Offline")
}
}
protocol Offline {
associatedtype Data
var data: Data { get set }
}
struct Model: Decodable, Offline {
var data: String = "abc..."
}
let h1 = HTTP()
h1.run { (r: Result<[String], Error>) in } // 1 - Print "Base" => OK
let h2 = HTTP()
h2.run { (r: Result<Model, Error>) in } // 2 - Print "Base" => ???
HTTP.handle { (r: Result<[String], Error>) in } // 3 - Print "Base" => OK
HTTP.handle { (r: Result<Model, Error>) in } // 4 - Print "Offline" => OK
I am trying to figure out why in case 2, it prints "Base" instead of "Offline". If anyone has suggestions so the right handle method get called depending on the given type T.
I made the handle method static for demo/running purpose to show it works in a static context (case 3 and 4). As you can see, called from the HTTP instance context behaviour is different (case 2).
Any idea ?
It looks like the instance function run(handler:) because it sets as a constraint the T to be only Decodable, filters in some way the Offline constraint. So, passes a type that is only Decodable to the static function handle(handler:) and the compiler assumes that the callable function is the one with only Decodable as a constraint.I do not know if this is understandable.
You can have the expected behavior by adding an overload for your instance function in HTTP class:
class HTTP {
func run<T: Decodable>(handler: (Result<T, Error>) -> Void) {
HTTP.handle(handler: handler)
}
func run<T: Decodable & Offline>(handler: (Result<T, Error>) -> Void) {
HTTP.handle(handler: handler)
}
}
The correct HTTP.handle to call is decided at compile time, and baked into the binary. T is only promised to be Decodable in run. It might conform to other protocols, but that's all that's promised. So it compiles this into a call to the Decodable version, even if you call it with something that could be Offline.
This gets to the point of generic specializations. It's not intended to change behavior. It's intended generally to improve performance. For example, consider the following:
func f<Seq: Sequence>(_ seq: Seq) -> Bool { ... }
func f<Seq: RandomAccessCollection>(_ seq: Seq) -> Bool { ... }
Every RandomAccessCollection is a Sequence, so one or the other might be called for an Array. Both should always return the same result. But the second might be more efficient in cases where the system can prove that Seq is Array. If they returned different results, it's not going to work correctly.
Generics are not a way to reinvent class inheritance. If you really need class inheritance, then use classes and inheritance. But generally you should redesign your system to avoid that. How to do that depends on the real goal here.

Is there a way to set the data type of the protocol in function pointer?

Is there a way to set the data type of the protocol in function pointer in swift?
Here's my protocol ICRUDOperation
public protocol ICRUDOperation {
associatedtype T
func insert(data:T)
func update(data:T)
func get(data:T) -> [T]
func getList(data: BaseModel) -> [T]
func getPage(data: BaseModel) -> [T]
func delete(data: T)
}
Which I try to use in:
func delegate1<W>(sqlite: W, service: W, data: W.T) where W: ICRUDOperation {
sqlite.insert(data: data)
}
var decision = [String : [String:((ICRUDOperation, ICRUDOperation, T) ->())?]]()
func fillDecision() {
decision["Person"]?["1"] = Delegate1
}
I get this error in decision
Protocol 'ICRUDOperation' can only be used as a generic constraint because it has Self or associated type requirements
Error for fillDecision():
Cannot assign value of type '(_, _, _.T) -> ()' to type '((ICRUDOperation, ICRUDOperation, _) -> ())??'
Once you've added an associated type, there is no longer any such thing as a "ICRUDOperation". A PAT (protocol with associated type) has no existential form; it exists in order to attach methods to other types, or to restrict what concrete types may be passed to a generic function. You cannot store a PAT in a variable or dictionary or anywhere else. A protocol (and doubly-so a PAT) is not an abstract class.
The most critical thing to understand is that associated types are selected by the implementation, not by the caller. So in your example, T would be selected by the implementation of ICRUDOperation (in the same way that Array chooses its Collection.Index to be Int; you don't get to pick that). Generics allow the caller to select the type, which looks more like what you're trying to achieve.
How you resolve this depends on your use case, which is difficult to understand from your example. What is the goal of decision?
It would be helpful if you would demonstrate what you expect two or three different implementations of ICRUDOperation would look like. I'm not sure what you intend "an implementation of an operation" to mean.
I am trying to understand how you want to use this so this my idea of how to use the protocol. I am not sure if this answers your question but maybe it can help getting you closer to a solution.
Say we have this model we want to persist
struct Item {
var id: Int
var name: String
}
Then we need a handler that can perform the db operations
struct ItemDbHandler: ICRUDOperation {
typealias T = Item
func insert(data: Item) {
print("\(#function) \(item)")
}
func update(data: Item) {
print("\(#function) \(item)")
}
func get(data: Item) -> [Item] { //shouldn't this return 1 element
print("\(#function) \(item)")
return []
}
// and so on...
}
And with some delegate function
func delegateUpdate<W>(sqlite: W, service: W, data: W.T) where W: ICRUDOperation {
sqlite.update(data: data)
}
we can either work with the handler directly or via the function
var item = Item(id: 1, name: "ABC")
var handler = ItemDbHandler()
handler.insert(data: item)
item.name = "abc"
delegateUpdate(sqlite: handler, service: handler, data: item)
Running this in a playground yields
insert(data:) Item(id: 1, name: "ABC")
update(data:) Item(id: 1, name: "abc")
I don't understand what you want to do fillDecision so I skipped it for now.

Swift protocols and equatable

I'm still learning how to work with arrays of objects implementing protocols with associated types.
I have the following protocols:
public protocol Word : Equatable, Hashable { // compiles
associatedtype WordType : Equatable
var moreWords: [WordType] { get }
}
public protocol WordDataSource { // compiles
associatedtype SomeWord : Word
func findWord(spelling: String) -> SomeWord?
}
I have WordA, WordB and WordC all implementing Word and subclassing NSObject
Basically, I want to implement the datasource protocol using different kinds of class implementing the Word class. This is the kind of code I would like to write, but obviously it doesn't compile.
class MyDataSource : WordDataSource {
func findWord(spelling: String) -> SomeWord? {
if conditionA {
return WordA()
}
if conditionB {
return WordB()
}
if conditionA {
return WordC()
}
}
}
Is that even possible in Swift? What should I write to make that work?
Thanks a lot for your help!
This is not possible, and it's not possible for a reason. Let's assume that your class MyDataSource does compile. Now, we could write such code:
let fooWord = MyDataSource().findWord(spelling: "Foo") // Would return WordA instance
let barWord = MyDataSource().findWord(spelling: "Bar") // Would return WordB instance
but all we know about those two types is that they are of this SomeWord type. So they should be comparable, since Word is comparable, right?
But they're two completely different types, so how would you know how should they be compared? Take a look at the definition of Equatable protocol:
public static func ==(lhs: Self, rhs: Self) -> Bool
You can only compare two objects of the same type that conform to this protocol.

Declare a Swift protocol which has a property return value CollectionType<Int>?

Is something like
protocol A {
var intCollection: CollectionType<Int> { get }
}
or
protocol A {
typealias T: CollectionType where T.Generator.Element == Int
var intCollection: T
}
possible in Swift 2.1?
Update for Swift 4
Swift 4 now support this feature! read more in here
Not as a nested protocol, but it's fairly straightforward using the type erasers (the "Any" structs).
protocol A {
var intCollection: AnyRandomAccessCollection<Int> { get }
}
This is actually often quite convenient for return values because the caller usually doesn't care so much about the actual type. You just have to throw a return AnyRandomAccessCollection(resultArray) at the end of your function and it all just works. Lots of stdlib now returns Any erasers. For the return value problem, it's almost always the way I recommend. It has the nice side effect of making A concrete, so it's much easier to work with.
If you want to keep the CollectionType, then you need to restrict it at the point that you create a function that needs it. For example:
protocol A {
typealias IntCollection: CollectionType
var intCollection: IntCollection { get }
}
extension A where IntCollection.Generator.Element == Int {
func sum() -> Int {
return intCollection.reduce(0, combine: +)
}
}
This isn't ideal, since it means you can have A with the wrong kind of collection type. They just won't have a sum method. You also will find yourself repeating that "where IntCollection.Generator.Element == Int" in a surprising number of places.
In my experience, it is seldom worth this effort, and you quickly come back to Arrays (which are the dominant CollectionType anyway). But when you need it, these are the two major approaches. That's the best we have today.
You can't do this upright as in your question, and there exists several thread here on SO on the subject of using protocols as type definitions, with content that itself contains Self or associated type requirements (result: this is not allowed). See e.g. the link provided by Christik, or thread Error using associated types and generics.
Now, for you example above, you could do the following workaround, however, perhaps mimicing the behaviour you're looking for
protocol A {
typealias MyCollectionType
typealias MyElementType
func getMyCollection() -> MyCollectionType
func printMyCollectionType()
func largestValue() -> MyElementType?
}
struct B<U: Comparable, T: CollectionType where T.Generator.Element == U>: A {
typealias MyCollectionType = T
typealias MyElementType = U
var myCollection : MyCollectionType
init(coll: MyCollectionType) {
myCollection = coll
}
func getMyCollection() -> MyCollectionType {
return myCollection
}
func printMyCollectionType() {
print(myCollection.dynamicType)
}
func largestValue() -> MyElementType? {
guard var largestSoFar = myCollection.first else {
return nil
}
for item in myCollection {
if item > largestSoFar {
largestSoFar = item
}
}
return largestSoFar
}
}
So you can implement blueprints for your generic collection types in you protocol A, and implement these blueprints in the "interface type" B, which also contain the actual collection as a member property. I have taken the largestValue() method above from here.
Example usage:
/* Examples */
var myArr = B<Int, Array<Int>>(coll: [1, 2, 3])
var mySet = B<Int, Set<Int>>(coll: [10, 20, 30])
var myRange = B<Int, Range<Int>>(coll: 5...10)
var myStrArr = B<String, Array<String>>(coll: ["a", "c", "b"])
myArr.printMyCollectionType() // Array<Int>
mySet.printMyCollectionType() // Set<Int>
myRange.printMyCollectionType() // Range<Int>
myStrArr.printMyCollectionType() // Array<String>
/* generic T type constrained to protocol 'A' */
func printLargestValue<T: A>(coll: T) {
print(coll.largestValue() ?? "Empty collection")
}
printLargestValue(myArr) // 3
printLargestValue(mySet) // 30
printLargestValue(myRange) // 10
printLargestValue(myStrArr) // c

Circular dependencies between generic types (CollectionType and its Index/Generator, e.g.)

Given a struct-based generic CollectionType …
struct MyCollection<Element>: CollectionType, MyProtocol {
typealias Index = MyIndex<MyCollection>
subscript(i: Index) -> Element { … }
func generate() -> IndexingGenerator<MyCollection> {
return IndexingGenerator(self)
}
}
… how would one define an Index for it …
struct MyIndex<Collection: MyProtocol>: BidirectionalIndexType {
func predecessor() -> MyIndex { … }
func successor() -> MyIndex { … }
}
… without introducing a dependency cycle of death?
The generic nature of MyIndex is necessary because:
It should work with any type of MyProtocol.
MyProtocol references Self and thus can only be used as a type constraint.
If there were forward declarations (à la Objective-C) I would just[sic!] add one for MyIndex<MyCollection> to my MyCollection<…>. Alas, there is no such thing.
A possible concrete use case would be binary trees, such as:
indirect enum BinaryTree<Element>: CollectionType, BinaryTreeType {
typealias Index = BinaryTreeIndex<BinaryTree>
case Nil
case Node(BinaryTree, Element, BinaryTree)
subscript(i: Index) -> Element { … }
}
Which would require a stack-based Index:
struct BinaryTreeIndex<BinaryTree: BinaryTreeType>: BidirectionalIndexType {
let stack: [BinaryTree]
func predecessor() -> BinaryTreeIndex { … }
func successor() -> BinaryTreeIndex { … }
}
One cannot (yet?) nest structs inside generic structs in Swift.
Otherwise I'd just move BinaryTreeIndex<…> inside BinaryTree<…>.
Also I'd prefer to have one generic BinaryTreeIndex,
which'd then work with any type of BinaryTreeType.
You cannot nest structs inside structs because they are value types. They aren’t pointers to an object, instead they hold their properties right there in the variable. Think about if a struct contained itself, what would its memory layout look like?
Forward declarations work in Objective-C because they are then used as pointers. This is why the indirect keyword was added to enums - it tells the compiler to add a level of indirection via a pointer.
In theory the same keyword could be added to structs, but it wouldn’t make much sense. You could do what indirect does by hand instead though, with a class box:
// turns any type T into a reference type
final class Box<T> {
let unbox: T
init(_ x: T) { unbox = x }
}
You could the use this to box up a struct to create, e.g., a linked list:
struct ListNode<T> {
var box: Box<(element: T, next: ListNode<T>)>?
func cons(x: T) -> ListNode<T> {
return ListNode(node: Box(element: x, next: self))
}
init() { box = nil }
init(node: Box<(element: T, next: ListNode<T>)>?)
{ box = node }
}
let nodes = ListNode().cons(1).cons(2).cons(3)
nodes.box?.unbox.element // first element
nodes.box?.unbox.next.box?.unbox.element // second element
You could turn this node directly into a collection, by conforming it to both ForwardIndexType and CollectionType, but this isn’t a good idea.
For example, they need very different implementations of ==:
the index needs to know if two indices from the same list are at the same position. It does not need the elements to conform to Equatable.
The collection needs to compare two different collections to see if they hold the same elements. It does need the elements to conform to Equatable i.e.:
func == <T where T: Equatable>(lhs: List<T>, rhs: List<T>) -> Bool {
// once the List conforms to at least SequenceType:
return lhs.elementsEqual(rhs)
}
Better to wrap it in two specific types. This is “free” – the wrappers have no overhead, just help you build the right behaviours more easily:
struct ListIndex<T>: ForwardIndexType {
let node: ListNode<T>
func successor() -> ListIndex<T> {
guard let next = node.box?.unbox.next
else { fatalError("attempt to advance past end") }
return ListIndex(node: next)
}
}
func == <T>(lhs: ListIndex<T>, rhs: ListIndex<T>) -> Bool {
switch (lhs.node.box, rhs.node.box) {
case (nil,nil): return true
case (_?,nil),(nil,_?): return false
case let (x,y): return x === y
}
}
struct List<T>: CollectionType {
typealias Index = ListIndex<T>
var startIndex: Index
var endIndex: Index { return ListIndex(node: ListNode()) }
subscript(idx: Index) -> T {
guard let element = idx.node.box?.unbox.element
else { fatalError("index out of bounds") }
return element
}
}
(no need to implement generate() – you get an indexing generator “for free” in 2.0 by implementing CollectionType)
You now have a fully functioning collection:
// in practice you would add methods to List such as
// conforming to ArrayLiteralConvertible or init from
// another sequence
let list = List(startIndex: ListIndex(node: nodes))
list.first // 3
for x in list { print(x) } // prints 3 2 1
Now all of this code looks pretty disgusting for two reasons.
One is because box gets in the way, and indirect is much better as the compiler sorts it all out for you under the hood. But it’s doing something similar.
The other is that structs are not a good solution to this. Enums are much better. In fact the code is really using an enum – that’s what Optional is. Only instead of nil (i.e. Optional.None), it would be better to have a End case for the end of the linked list. This is what we are using it for.
For more of this kind of stuff you could check out these posts.
While Airspeed Velocity's answer applies to the most common cases, my question was asking specifically about the special case of generalizing CollectionType indexing in order to be able to share a single Index implementation for all thinkable kinds of binary trees (whose recursive nature makes it necessary to make use of a stack for index-based traversals (at least for trees without a parent pointer)), which requires the Index to be specialized on the actual BinaryTree, not the Element.
The way I solved this problem was to rename MyCollection to MyCollectionStorage, revoke its CollectionType conformity and wrap it with a struct that now takes its place as MyCollection and deals with conforming to CollectionType.
To make things a bit more "real" I will refer to:
MyCollection<E> as SortedSet<E>
MyCollectionStorage<E> as BinaryTree<E>
MyIndex<T> as BinaryTreeIndex<T>
So without further ado:
struct SortedSet<Element>: CollectionType {
typealias Tree = BinaryTree<Element>
typealias Index = BinaryTreeIndex<Tree>
subscript(i: Index) -> Element { … }
func generate() -> IndexingGenerator<SortedSet> {
return IndexingGenerator(self)
}
}
struct BinaryTree<Element>: BinaryTreeType {
}
struct BinaryTreeIndex<BinaryTree: BinaryTreeType>: BidirectionalIndexType {
func predecessor() -> BinaryTreeIndex { … }
func successor() -> BinaryTreeIndex { … }
}
This way the dependency graph turns from a directed cyclic graph into a directed acyclic graph.