Extended capability for a more restrictive generic - swift

I have a generic binary search tree based on Comparable:
public class BSTree<T: Comparable> {
public func insert(_ val: T, _ n: Int) {
// ...
}
#discardableResult
public func delete(_ val: T, _ n: Int) -> Int {
// ...
}
}
I want to add the ability to provide the sum of the values, if T is an arithmetic type. I tried the following:
public class BSTree<T: Comparable> {
private var sumStorage: T?
public func insert(_ val: T, _ n: Int) {
if let arithVal = val as? AdditiveArithmetic {
for _ in 0 ..< n { sumStorage += arithVal }
}
// ...
}
#discardableResult
public func delete(_ val: T, _ n: Int) -> Int {
// ...
numDeleted = ...
if let arithVal = val as? AdditiveArithmetic {
for _ in 0 ..< numDeleted { sumStorage -= arithVal }
}
}
}
extension BSTree where T: AdditiveArithmetic {
public var sum: T {
sumStorage as? T ?? T.zero
}
}
Of course, when I try to cast val as AdditiveArithmetic I get “Protocol 'AdditiveArithmetic' can only be used as a generic constraint because it has Self or associated type requirements”. Plus sumStorage isn’t AdditiveArithmetic, so I can’t add to it, and I can’t make it a stored property of the extension, because ... you just can’t.
What I finally came up with was to use inheritance:
class SummedBSTree<T>: BSTree<T> where T: AdditiveArithmetic & Comparable {
public var sum = T.zero
override public func insert(_ val: T, _ n: Int) {
super.insert(val, n)
for _ in 0 ..< n { sum += val }
}
#discardableResult
override public func delete(_ val: T, _ n: Int) -> Int {
let numDeleted = super.delete(val, n)
for _ in 0 ..< numDeleted { sum -= val }
return numDeleted
}
}
This works, but it seems like it’s a case of using a sledgehammer where a jeweler’s screwdriver should be able to do the trick. It’s frustrating that something that would be so easy to do in Objective-C (and other less strongly typed languages) is so difficult in Swift. Can someone come up with a way of adding the summing capability without subclassing?

import UIKit
//https://stackoverflow.com/questions/61784548/swift-extended-capability-for-a-more-restrictive-generic
protocol ON1Speedable {
associatedtype Item: Comparable
var sumStorage: Item? { get set }
}
public class BSTree<T: Comparable> {
var sumStorage: T?
init(sumStorage: T? = nil) {
self.sumStorage = sumStorage
}
}
extension ON1Speedable where Item: AdditiveArithmetic, Item: Strideable, Item.Stride: SignedInteger {
mutating func insert(_ val: Item, _ n: Int) {
sumStorage = sumStorage ?? Item.zero
for _ in 0..<n { sumStorage! += val }
}
#discardableResult
mutating func delete(_ val: Item, _ n: Int) -> Item? {
sumStorage = sumStorage ?? Item.zero
for _ in Item.zero..<val { sumStorage! -= val }
return sumStorage
}
}
extension BSTree: ON1Speedable { }
var g2 = BSTree<Int>(sumStorage: 0)
g2.sumStorage
g2.insert(5, 5)
g2.sumStorage // 25
g2.delete(5, 5) // 0
var g3 = BSTree<String>()
g3.sumStorage // nil
//g3.insert("foo", 5) // Error: Referencing instance method 'insert' on 'ON1Speedable' requires that 'String.Stride' conform to 'SignedInteger'
g3.sumStorage // nil
//g3.delete("bar", 5) // Error: Referencing instance method 'delete' on 'ON1Speedable' requires that 'String.Stride' conform to 'SignedInteger'

Related

Error ... requires that 'Self.Key' conform to 'Hashable'

The code fragment below (nothing else in the playground) creates errors I cannot fathom. Any assistance would be appreciated.
protocol p: ExpressibleByDictionaryLiteral {
associatedtype T
var entries: [Int: T] {get set}
mutating func add( id:Int, e:T )->Bool
}
extension p {
init(dictionaryLiteral elements: (Int, T)...) {
self.init(initializeFrom: elements.reduce(into: [Key: Value](),
{ (result, tuple) in result[tuple.0] = tuple.1 } ))
}
init(initializeFrom: [Key: Value]) {
entries = initializeFrom
}
}
It looks like you want to constrain Key to be an Int and Value to be T.
Key and Value are already associated types on ExpressibleByDictionaryLiteral: https://developer.apple.com/documentation/swift/expressiblebydictionaryliteral
protocol p: ExpressibleByDictionaryLiteral where Key == Int, Value == T { // <-- Here
associatedtype T
var entries: [Int: T] {get set}
mutating func add( id:Int, e:T )->Bool
}
extension p {
init(dictionaryLiteral elements: (Int, T)...) {
self.init(initializeFrom: elements.reduce(into: [Int: T](),
{ (result, tuple) in result[tuple.0] = tuple.1 } ))
}
init(initializeFrom: [Key: Value]) {
self.init()
entries = initializeFrom
}
}
The final error in your screenshot is just a typo.

How to write mutating function for enum in Swift

I want to write mutating function like the following. But this code cannot be compiled because x and y are immutable and copied value. I want to get the reference of x and y. How to get the reference of variables wrapped by enum?
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func increment() {
switch self {
case let .apple(x):
x += 1
case let .banana(x, y, z):
x += 1
}
}
}
var a = Fruit.banana(100, 200, 300)
a.increment()
I know the following code can do the same thing. But I think this solution is redundant because we have to write each variable twice.
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func increment() {
switch self {
case let .apple(x):
self = .apple(x + 1)
case let .banana(x, y, z):
self = .banana(x + 1, y, z)
}
}
}
var a = Fruit.banana(100, 200, 300)
a.increment()
Using self = .apple(x) will do the trick. It is customary, but you already knew this.
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func increment() {
switch self {
case let .apple(x):
self = .apple(x + 1)
case let .banana(x, y, z):
self = .banana(x + 1, y + 1, z + 1)
}
}
}
var a = Fruit.banana(100, 200, 300)
a.increment()
You could also add support for generic operators:
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func operate(_ op: (Int, Int) -> Int,_ num: Int) {
switch self {
case let .apple(x):
self = .apple(op(x, num))
case let .banana(x, y, z):
self = .banana(op(x, num), op(y, num), op(z, num))
}
}
}
var a = Fruit.banana(100, 200, 300)
a.operate(+, 1) // adds all by 1
a.operate(*, 500) // multiplies all by 500
You could also add support for an array of generic operators:
enum Fruit {
case apple(Int)
case banana(Int, Int, Int)
mutating func operate(_ nest: [((Int, Int) -> Int, Int)]) {
for i in nest {
switch self {
case let .apple(x):
self = .apple(i.0(x, i.1))
case let .banana(x, y, z):
self = .banana(i.0(x, i.1), i.0(y, i.1), i.0(z, i.1))
}
}
}
}
var a = Fruit.banana(100, 200, 300)
a.operate([(+, 500), (*, 2)]) // Adds all by 500, then multiply all by 2
Here's a nice simplification
If it were up to me, this is what I would do to get rid of repeating self =. You can simplify this further if you wish.
enum FruitList: String { case apple, banana }
struct Fruit {
static func apple(_ one: Int) -> Fruit {
return Fruit.init(.apple, [one])
}
static func banana(_ one: Int,_ two: Int,_ three: Int) -> Fruit {
return Fruit.init(.apple, [one, two, three])
}
var picked: (FruitList, [Int])
init(_ fruit: FruitList,_ list: [Int]) {
picked = (fruit, list)
}
mutating func operate(_ nest: [((Int, Int) -> Int, Int)]) {
for i in nest {
for j in 0..<picked.1.count {
picked.1[j] = i.0(picked.1[j], i.1)
}
}
}
}
var a = Fruit.apple(100)
a.operate([(+, 500), (*, 2)]) // Add all by 500, then multiply all by 2

Enforcing generic protocol constraint on returning class

The following behaves as it should. Importantly, func1 and func2 return an interface to the MyClass object that is constrained to the MySecondClassProtocol
import Foundation
protocol MyIntProtocol: class {
var value: Int? { get set }
func fulfill(_ result: Int)
}
final class MyIntClass: MyIntProtocol {
var value: Int?
func fulfill(_ result: Int) { self.value = result }
}
protocol MyFirstClassProtocol: class {
func func1(_ value: MyIntProtocol) -> MySecondClassProtocol
}
protocol MySecondClassProtocol: class {
func func2(_ value: MyIntProtocol) -> MySecondClassProtocol
func func3(_ value: MyIntProtocol)
}
final class MyClass: MyFirstClassProtocol, MySecondClassProtocol {
func func1(_ value: MyIntProtocol) -> MySecondClassProtocol {
print(value.value!)
return self
}
func func2(_ value: MyIntProtocol) -> MySecondClassProtocol {
print(value.value!)
return self
}
func func3(_ value: MyIntProtocol) { print(value.value!) }
}
let e = MyIntClass()
e.fulfill(23)
let m = MyClass()
// m has func1, func2 and func3 methods
let n = m.func1(e)
// n has func2 and func3 methods
let o = n.func2(e)
// o has func2 and func3 methods
o.func3(e)
I would like to replicate this "return object with constraint to protocol" behaviour, however, where a generic class and its protocol are now introduced.
The following compiles, but does not constrain the returning object of func1 and func2 to the MySecondClassProtocol.
import Foundation
protocol MyGenericProtocol: class {
associatedtype ValueType
var value: ValueType? { get set }
func fulfill(_ result: ValueType)
}
final class MyGenericClass<T>: MyGenericProtocol {
var value: T?
func fulfill(_ result: T) { self.value = result }
}
protocol MyFirstClassProtocol: class {
associatedtype T: MyGenericProtocol
associatedtype U: MySecondClassProtocol
func func1(_ value: T) -> U
}
protocol MySecondClassProtocol: class {
associatedtype T: MyGenericProtocol
associatedtype U: Self
func func2(_ value: T) -> U
func func3(_ value: T)
}
final class MyClass: MyFirstClassProtocol, MySecondClassProtocol {
func func1(_ value: MyGenericClass<Int>) -> MyClass {
print(value.value!)
return self
}
func func2(_ value: MyGenericClass<Int>) -> MyClass {
print(value.value!)
return self
}
func func3(_ value: MyGenericClass<Int>) { print(value.value!) }
}
let e = MyGenericClass<Int>()
e.fulfill(23)
let m = MyClass()
// m has func1, func2 and func3 methods
let n = m.func1(e)
// n has func1, func2 and func3 methods
// Wanting only func2 and func3 methods available
let o = n.func2(e)
// o has func1, func2 and func3 methods
// Wanting only func2 and func3 methods available
o.func3(e)
How would I go about achieving this? Thanks!!
This appears to be what I was looking for. It constrains the return objects to the correct protocols.
import Foundation
protocol MyGenericProtocol: class {
associatedtype ValueType
var value: ValueType? { get set }
func fulfill(_ result: ValueType)
}
final class MyGenericClass<T>: MyGenericProtocol {
var value: T?
func fulfill(_ result: T) { self.value = result }
}
protocol MyFirstClassProtocol: class {
func func1<T>(_ value: T) -> MySecondClassProtocol where T: MyGenericProtocol
}
protocol MySecondClassProtocol: class {
func func2<T>(_ value: T) -> MySecondClassProtocol where T: MyGenericProtocol
func func3<T>(_ value: T) where T: MyGenericProtocol
}
final class MyClass: MyFirstClassProtocol, MySecondClassProtocol {
func func1<T>(_ value: T) -> MySecondClassProtocol where T: MyGenericProtocol {
print(value.value!)
return self
}
func func2<T>(_ value: T) -> MySecondClassProtocol where T: MyGenericProtocol {
print(value.value!)
return self
}
func func3<T>(_ value: T) where T: MyGenericProtocol {
print(value.value!)
}
}
let e = MyGenericClass<Int>()
e.fulfill(23)
let m = MyClass()
// m has func1, func2 and func3 methods
let n = m.func1(e)
// n has func2 and func3 methods
let o = n.func2(e)
// o has func2 and func3 methods
o.func3(e)

Automatically have += defined when defining +?

I have a type that has a custom + defined for it. I was wondering if it was possible for Swift to automatically write a definition for +=, namely a += b --> a = a+b. Ideally I would not have to write the corresponding assignment operator for each operator I write.
Sample code:
class A {
var value: Int
init(_ value: Int) {
self.value = value
}
static func +(lhs: A, rhs: A) -> A {
return A(lhs.value + rhs.value)
}
}
var a = A(42)
let b = A(10)
// OK
let c = a + b
// error: binary operator '+=' cannot be applied to two 'A' operands
// Ideally, this would work out of the box by turning it into a = a+b
a += b
Usually you have to define += when you define +.
You could create a Summable protocol that declares both + and +=, but you'll still have to define the + function since addition of arbitrary types has no concrete meaning. Here's an example:
protocol Summable {
static func +(lhs: Self, rhs: Self) -> Self
static func +=(lhs: inout Self, rhs: Self)
}
extension Summable {
static func +=(lhs: inout Self, rhs: Self) { lhs = lhs + rhs }
}
struct S: Summable { }
func +(lhs: S, rhs: S) -> S {
// return whatever it means to add a type of S to S
return S()
}
func f() {
let s0 = S()
let s1 = S()
let _ = s0 + s1
var s3 = S()
s3 += S() // you get this "for free" because S is Summable
}

Is there any way to determine sub-protocol conformance for instance conforming to generic protocol in Swift 2 (at runtime or during compilation)?

I'm porting Java library to Swift 2.0 and have some troubles with generics.
I have following protocol hierarchy:
public protocol Graph {
typealias V: Hashable
typealias E: Hashable
func getAllEdges(sourceVertex: V, targetVertex: V) -> Set<E>?
func getEdge(sourceVertex: V, targetVertex: V) -> E?
func getEdgeFactory() -> EdgeFactory<V, E>?
func addEdge(sourceVertex: V, targetVertex: V) -> E?
func addEdge(sourceVertex: V, targetVertex: V, e: E) -> Bool
func addVertex(v: V) -> Bool
func containsEdge(sourceVertex: V, targetVertex: V) -> Bool
func containsEdge(e: E) -> Bool
func containsVertex(v: V) -> Bool
func edgeSet() -> Set<E>
func edgesOf(v: V) -> Set<E>
func removeAllEdges<T: CollectionType where T.Generator.Element == E>(edges: T) -> Bool
func removeAllEdges(sourceVertex: V, targetVertex: V) -> Set<E>?
func removeAllVertices<T: CollectionType where T.Generator.Element == V>(vertices: T) -> Bool
func removeEdge(sourceVertex: V, targetVertex: V)
func removeEdge(e: E) -> Bool
func removeVertex(v: V) -> Bool
func vertexSet() -> Set<V>
func getEdgeSource(e: E) -> V
func getEdgeTarget(e: E) -> V
func getEdgeWeight(e: E) -> Double
}
public protocol DirectedGraph: Graph {
func inDegreeOf(vertex: V) -> Int
func incomingEdgesOf(vertex: V) -> Set<E>
func outDegreeOf(vertex: V) -> Int
func outgoingEdgesOf(vertex: V) -> Set<E>
}
public protocol UndirectedGraph: Graph {
func degreeOf(vertex: V) -> Int
}
And here's definition of class which causes trouble:
public class CrossComponentIterator
<V: Hashable, E: Hashable, D, G: Graph
where G.V == V, G.E == E>
: AbstractGraphIterator<V, E>
Namely, it has method which should init one of its variables based on actual type of graph passed - DirectedGraph or UndirectedGraph.
I've tried solving this by declaring multiple versions of the function which does this:
func createGraphSpecifics<DG: Graph where DG: DirectedGraph, DG.V == V, DG.E == E>(graph: DG)
-> CrossComponentIteratorSpecifics<V, E>
{
return DirectedSpecifics<V, E, DG>(graph: graph)
}
func createGraphSpecifics<UG: Graph where UG: UndirectedGraph, UG.V == V, UG.E == E>(graph: UG)
-> CrossComponentIteratorSpecifics<V, E>
{
return UndirectedSpecifics<V, E, UG>(graph: graph)
}
func createGraphSpecifics<GG: Graph where GG.V == V, GG.E == E>(graph: GG)
-> CrossComponentIteratorSpecifics<V, E>
{
fatalError("Unknown graph type instance")
}
But unfortunately, only last version of function is called for any instance of graph (even if it conforms to "DirectedGraph" or "UndirectedGraph")
And I know, that probably I can solve this problem by converting protocols DirectedGraph and UndirectedGraph to abstract classes
(by that I mean classes with fatalError() in each declared function since Swift doesn't support abstract classes de jure).
But maybe there is another, more elegant and Swifty solution?
In Java this is trivial - conformance to interface is checked at runtime:
if (g instanceof DirectedGraph<?, ?>) {
return new DirectedSpecifics<V, E>((DirectedGraph<V, E>) g);
} else {
return new UndirectedSpecifics<V, E>(g);
}
Edit here's minimal code for what I'm trying to achieve:
protocol P {
// This typealias makes impossible to use 'P'
// (or its descendants) as a type.
// It can be used only as generic constraint.
typealias A
// myfunc is needed for compiler to infer 'A'
func myfunc(a: A)
}
protocol P1:P {
func p1specific(a: A)
}
protocol P2:P {
func p2specific(a: A)
}
struct S<T:P> {
init(t: T) {
// TODO: check if 't' conforms to 'P1', 'P2', both or neither
}
}
// Examples of concrete implementations of 'P1' and 'P2'
struct S1<X>:P1{
func myfunc(a: X) {}
func p1specific(a: X) {}
}
struct S2<X>:P2{
func myfunc(a: X) {}
func p2specific(a: X) {}
}
Is there any way to determine sub-protocol conformance for instance
conforming to generic protocol in Swift 2 (at runtime or during
compilation)?
Yes.
Here's my trick for achieving type erasure, hence allowing one to utilize the runtime. Observe _P:
protocol _P {
static var _A: Any.Type { get }
func _myfunc(_a: Any) -> Void?
}
extension _P where Self: P {
static var _A: Any.Type {
return A.self
}
func _myfunc(_a: Any) -> Void? {
return (_a as? A).map(myfunc)
}
}
protocol P {
typealias A
func myfunc(a: A)
}
protocol _P1:_P {
func _p1specific(_a: Any) -> Void?
}
extension _P1 where Self: P1 {
func _p1specific(_a: Any) -> Void? {
return (_a as? A).map(p1specific)
}
}
protocol P1:_P1, P {
func p1specific(a: A)
}
protocol _P2:_P {
func _p2specific(_a: Any) -> Void?
}
extension _P2 where Self: P2 {
func _p2specific(_a: Any) -> Void? {
return (_a as? A).map(p2specific)
}
}
protocol P2:_P2, P {
func p2specific(a: A)
}
You can now determine whether a value conforms to P1 or P2, and force cast accordingly. Additionally, the generic parameter A is now available via the opaque Any.Type.
(x as? _P1) != nil ? true : false
import XCPlayground
import Foundation
protocol P {}
protocol P1:P {}
protocol P2:P {}
struct S1:P1{}
struct S2:P2{}
struct S<T:P> {
var p1: P1?
var p2: P2?
init(t: T) {
p1 = t as? P1
p2 = t as? P2
}
}
let p1 = S1()
let p2 = S2()
let s1 = S(t: p1)
let s2 = S(t: p2)
dump(s1)
dump(s2)
/*
▿ S<S1>
▿ p1: S1
- Some: S1
- p2: nil
▿ S<S2>
- p1: nil
▿ p2: S2
- Some: S2
*/
use
g is Type // trur or false
and
let v2 = v1 as? Type // v2 = v2 or nil
in swift
update
protocol P {
typealias A
}
protocol P1:P {}
protocol P2:P {}
struct S1:P1{
typealias A = Int
}
struct S2:P2{
typealias A = Double
}
struct S<T:P> {
var p1: S1?
var p2: S2?
init(t: T) {
p1 = t as? S1
p2 = t as? S2
}
}
let p1 = S1()
let p2 = S2()
let s1 = S(t: p1)
let s2 = S(t: p2)
.....
protocol P {
// This typealias makes impossible to use 'P'
// (or its descendants) as a type.
// It can be used only as generic constraint.
typealias A
// myfunc is needed for compiler to infer 'A'
func myfunc(a: A)
}
protocol P1:P {}
protocol P2:P {}
// aka 'abstract' conforming to P1
struct S1:P1{
typealias A = AnyObject
func myfunc(a: A) {}
}
// aka 'abstract' conforming to P2
struct S2:P2{
typealias A = Int
func myfunc(a: A) {}
}
// generic struct with type conforming to P
struct S<T:P> {
init(t: T) {
// TODO: check if 't' conforms to 'P1', 'P2', both or neither
if t is S1 {
print("t conforms to P1, because it is type S1")
}
if t is S2 {
print("t conforms to P2, besause it is type S2")
}
}
}
let s1 = S(t: S1()) // t conforms to P1, because it is type S1
let s2 = S(t: S2()) // t conforms to P2, besause it is type S2
// WARNING !!!!!!
// var s = s1
// s = s2 // error: cannot assign value of type 'S<S2>' to type 'S<S1>'