Protocol Having generic function and associatedType - swift

I've the following code:
protocol NextType {
associatedtype Value
associatedtype NextResult
var value: Value? { get }
func next<U>(param: U) -> NextResult
}
struct Something<Value>: NextType {
var value: Value?
func next<U>(param: U) -> Something<Value> {
return Something()
}
}
Now, the problem is in the Something implementation of next. I want to return Something<U> instead of Something<Value>.
But when I do that I got the following error.
type 'Something<Value>' does not conform to protocol 'NextType'
protocol requires nested type 'Value'

I tested the following codes and they compile (Xcode 7.3 - Swift 2.2). In this state they are not very useful, but I hope it helps you to find the final version you need.
Version 1
Since, Something is defined using V, I think you can't return just Something<U>. But you can redefine Something using U and V like this:
protocol NextType {
associatedtype Value
associatedtype NextResult
var value: Value? { get }
func next<U>(param: U) -> NextResult
}
struct Something<V, U>: NextType {
typealias Value = V
typealias NextResult = Something<V, U>
var value: Value?
func next<U>(param: U) -> NextResult {
return NextResult()
}
}
let x = Something<Int, String>()
let y = x.value
let z = x.next("next")
Version 2
Or just define Something using V:
protocol NextType {
associatedtype Value
associatedtype NextResult
var value: Value? { get }
func next<U>(param: U) -> NextResult
}
struct Something<V>: NextType {
typealias Value = V
typealias NextResult = Something<V>
var value: Value?
func next<V>(param: V) -> NextResult {
return NextResult()
}
}
let x = Something<String>()
let y = x.value
let z = x.next("next")

Related

Swift Associated type constraints

I have two protocols with each defining an associated type. One of the protocols needs to define a variable of typed the other protocol where they both have the same type for associated type. Is it possible to somehow infer the type of associated type?
protocol A {
associatedtype AModel
var b: B { get }
}
protocol B {
associatedtype BModel
func doAnother(anotherModel: BModel)
}
Here is what I tried with no success
protocol A {
associatedtype AModel
associatedtype TypedB = B where B.BModel == AModel
var another: TypedB { get }
}
protocol B {
associatedtype BModel
func doAnother(anotherModel: BModel)
}
Please find the following working playground example. You need to use the associated type's name, not the constraining protocol's name. The reason for this is described here.
import Foundation
protocol A {
associatedtype AModel
associatedtype TypedB: B where TypedB.BModel == AModel
var another: TypedB { get }
}
protocol B {
associatedtype BModel
func doAnother(anotherModel: BModel)
}
// compiles
struct One: B {
typealias BModel = String
func doAnother(anotherModel: String) {}
}
struct Second: A {
typealias AModel = String
typealias TypedB = One
var another: One
}
// does not compile
struct Third: B {
typealias BModel = Int
func doAnother(anotherModel: Int) {}
}
struct Fourth: A { // A' requires the types 'Fourth.AModel' (aka 'String') and 'Third.BModel' (aka 'Int') be equivalent
typealias AModel = String
typealias TypedB = Third
var another: Third
}

Create an array of protocols with constrained associated types

This is a basic example of creating an array of protocols with associated types using type erasure:
protocol ProtocolA {
associatedtype T
func doSomething() -> T
}
struct AnyProtocolA<T>: ProtocolA {
private let _doSomething: (() -> T)
init<U: ProtocolA>(someProtocolA: U) where U.T == T {
_doSomething = someProtocolA.doSomething
}
func doSomething() -> T {
return _doSomething()
}
}
Creating an array of them isn't hard:
let x: [AnyProtocolA<Any>] = []
Is there any way way I can create an array of protocols which have associated types that are constrained? This is what I have tried:
protocol Validateable {
// I removed the functions and properties here to omit unreleveant code.
}
protocol ProtocolA {
associatedtype T: Validateable
func doSomething() -> T
}
struct AnyProtocolA<T: Validateable>: ProtocolA {
private let _doSomething: (() -> T)
init<U: ProtocolA>(someProtocolA: U) where U.T == T {
_doSomething = someProtocolA.doSomething
}
func doSomething() -> T {
return _doSomething()
}
}
It compiles! But didn't it defeated the chance of creating an array of AnyProtocolA's now? Now I can't use type Any as a placeholder in my array.
How do I create an array of AnyProtocolA's which has a constrained associated type? Is it even possible? This won't work since Any ofcourse doesn't conform to Validateable:
let x: [AnyProtocolA<Any>] = []
Extending Any can't be done:
extension Any: Validateable {} // Non nominal type error
Edit:
I think I already found it, just type erasure the protocol Validateable as well:
protocol Validateable {
// I removed the functions and properties here to omit unreleveant code.
}
protocol ProtocolA {
associatedtype T: Validateable
func doSomething() -> T
}
struct AnyProtocolA<T: Validateable>: ProtocolA {
private let _doSomething: (() -> T)
init<U: ProtocolA>(someProtocolA: U) where U.T == T {
_doSomething = someProtocolA.doSomething
}
func doSomething() -> T {
return _doSomething()
}
}
struct AnyValidateable<T>: Validateable {}
Now I can use it as:
let x: [AnyProtocolA<AnyValidateable<Any>>] = []
Any answers that are better are always welcome :)

Can I specify that a class instance can be converted to some type?

Say I have a generic class
class Foo<T> { … }
Can I somehow specify that instances of this class can be converted to T in assignments? Example:
let foo = Foo<Int>()
func useAnInt(a: Int) {}
let getTheInt: Int = foo
useAnInt(foo)
Why not just use the underlying type? (Similar to #MrBeardsley's answer)
class Foo<T> {
var t : T
init(t: T) {
self.t = t
}
}
let foo = Foo(t: 3)
func useAnInt(a: Int) {}
let getTheInt: Int = foo.t
useAnInt(foo.t)
You are not able to do what you are asking. Even though Foo defines a generic type T, instances of Foo are still Foo and cannot be converted to the generic type. The reason you would declare a generic type at the class level is to use it multiple places throughout the class.
class Foo<T> {
var value: T
init(withValue: T) {
self.value = withValue
}
func getSomeValue() -> T {
return self.value
}
}
Generics don't mean the class itself is generic and can be converted.
One way of achieving what you want is to use a dedicated protocol for each of the target types that your class shall be convertible to. Here is very basic example:
protocol BoolAdaptable {
func adaptToBool() -> Bool
}
protocol IntAdaptable {
func adaptToInt() -> Int
}
protocol FloatAdaptable {
func adaptToFloat() -> Float
}
class Foo: BoolAdaptable, IntAdaptable, FloatAdaptable {
var v: NSNumber
init(_ v: NSNumber) {
self.v = v
}
func adaptToBool() -> Bool {
return v.boolValue
}
func adaptToInt() -> Int {
return v.integerValue
}
func adaptToFloat() -> Float {
return v.floatValue
}
}
let foo = Foo(NSNumber(double: 1.23))
let getTheBool = foo.adaptToBool() // true
let getTheInt = foo.adaptToInt() // 1
let getTheFloat = foo.adaptToFloat() // 1.23
This could easily be extended to support more complex conversions.

How to make a mutating function in an extension return Int using Swift?

Why doesn't this code work?
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
var x:Int = 7
let y:Int = x.adjust()
here is what I get on XCODE
is there a way to make adjust() return Int without changing its definition in the protocol?
Yes, you can give adjust a return value. Define it to return an Int in the protocol and class, then have it return itself in the mutating method:
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust() -> Int
}
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() -> Int {
self += 42
return self
}
}
var x:Int = 7
let y:Int = x.adjust() //49
Because the adjust() function does not return value (it just change the value of its instance), you can achieve this by this orders:
var x:Int = 7
x.adjust() //adjust x self value
let y:Int = x //assigne x value to y
Hope this helps.
Ques : is there a way to make adjust() return Int without changing its definition in the protocol?
Ans : No
The definition/signature of a method tells us what it's going to take as input and what data type it's going to return.
You need to return an Int from a method then it's signature should end with -> Int. That's the syntax ! Can't change it.
connor has provided the right piece of code you need.

Why is generic type information lost in generic functions with a Comparable constraint?

When creating a normal generic function without constraints it works as intended, i.e:
func select<T,U>(x:T, f:(T) -> U) -> U {
return f(x)
}
The type flows through into the closure argument where it lets me access it as the strong type, i.e:
var b1:Bool = select("ABC") { $0.hasPrefix("A") }
var b2:Bool = select(10) { $0 > 0 }
It continues to work when I add an Equatable constraint:
func selectEquatable<T : Equatable, U : Equatable>(x:T, f:(T) -> U) -> U {
return f(x)
}
var b3:Bool = selectEquatable("ABC") { $0.hasPrefix("A") }
But for some reason fails when using a Comparable constraint:
func selectComparable<T : Comparable, U : Comparable>(x:T, f:(T) -> U) -> U {
return f(x)
}
var b4:Bool = selectComparable("ABC") { $0.hasPrefix("A") }
Fails with the build error:
Could not find member 'hasPrefix'
But it does allow returning itself where the type flows through as a String
var b5:String = selectComparable("ABC") { $0 }
Looking at the API docs shows that String is Comparable:
extension String : Comparable {
}
and it even allows implicit casting from a String to a Comparable:
var str:Comparable = ""
So why can't I access it as a strong-typed String inside my Closure?
var b4:Bool = selectComparable("ABC") { $0.hasPrefix("A") } //build error
It's not the String. Your closure { $0.hasPrefix("A") } has the return type Bool, which is assigned to U. Bool is Equatable, but not Comparable.
You probably want the closure to return Bool, but selectComparable to return U.
Edit
Here's evidence that returning a String (which is Comparable) instead of a Bool (not Comparable) will compile:
func selectComparable<T: Comparable, U: Comparable>(x:T, f:(T) -> U) -> U {
return f(x)
}
var b4 = selectComparable("ABC") { (str: String) -> String in str }
Your selectComparable declaration is incorrect.
func selectComparable<T: Comparable, U: Comparable>(x:T, f:(T) -> U) -> U {
return f(x)
}
U: Comparable cannot hold for type Bool, it is not Comparable, only Equatable
This will work fine
func selectComparable<T: Comparable, U>(x:T, f:(T) -> U) -> U {
return f(x)
}
as will
func select<T:Comparable,U: Equatable>(x:T, f:(T) -> U) -> U {
return f(x)
}