Swift: Differencebetween a Typealias and an Associatedtype with a Value in a Protocol

Protocol associatedType and

Defined associated type makes classes which conform protocol strong typed. This provide compile-time error handling.

In other hand, generic type makes classes which conform protocol more flexible.

For example:

protocol AssociatedRepository {
associatedtype T
func add(data : T) -> Bool
}

protocol GenericRepository {
func add<T>(data : T) -> Bool
}

class A: GenericRepository {
func add<T>(data : T) -> Bool {
return true
}
}

class B: AssociatedRepository {
typealias T = UIViewController
func add(data : T) -> Bool {
return true
}
}

class A could put any class into add(data:) function, so you need to makes your sure that function handle all cases.

A().add(data: UIView())
A().add(data: UIViewController())

both would be valid

But for class B you will get compile-time error when you will try to put anything except UIViewController

B().add(data: UIView()) // compile-time error here
B().add(data: UIViewController())

protocol associated type typealias assignment compile error

In this case the assignment of Int to the typealias is equal to no assignment because it gets overridden by your conforming type:

// this declaration is equal since you HAVE TO provide the type for SomeType
protocol SomeProtocol {
typealias SomeType

func someFunc(someVar: SomeType)
}

Such an assignment provides a default type for SomeType which gets overridden by your implementation in SomeClass, but it is especially useful for protocol extensions:

protocol Returnable {
typealias T = Int // T is by default of type Int
func returnValue(value: T) -> T
}

extension Returnable {
func returnValue(value: T) -> T {
return value
}
}

struct AStruct: Returnable {}

AStruct().returnValue(3) // default signature: Int -> Int

You get the function for free only by conforming to the protocol without specifying the type of T. If you want to set your own type write typealias T = String // or any other type in the struct body.

Some additional notes about the provided code example

You solved the problem because you made it explicit which type the parameter has. Swift also infers your used type:

class SomeClass: SomeProtocol {
func someFunc(someVar: Double) {
print(someVar)
}
}

So SomeType of the protocol is inferred to be Double.

Another example where you can see that SomeType in the class declaration doesn't refer to to the protocol:

class SomeClass: SomeProtocol {
typealias Some = Int
func someFunc(someVar: Some) {
print(someVar)
}
}

// check the type of SomeType of the protocol
// dynamicType returns the current type and SomeType is a property of it
SomeClass().dynamicType.SomeType.self // Int.Type
// SomeType gets inferred form the function signature

However if you do something like that:

protocol SomeProtocol {
typealias SomeType: SomeProtocol

func someFunc(someVar: SomeType)
}

SomeType has to be of type SomeProtocol which can be used for more explicit abstraction and more static code whereas this:

protocol SomeProtocol {
func someFunc(someVar: SomeProtocol)
}

would be dynamically dispatched.

Unable to use associatedType as method returnType in swift as compiler throws Ambiguous inference of associated type

Using an opaque return type (i.e. some) is not required for what you want to do. When you go to implement the Office protocol, just return the actual type from the function and computed property you specified and the compiler will infer the associatedtype for you:

protocol DummyOffice {}

struct EmptyOffice: DummyOffice {}

protocol Office {
associatedtype SubBranch: DummyOffice
var subBranch: SubBranch { get }
func getSubBranch() -> SubBranch
}

struct Apple: Office {
let emptyOffice = EmptyOffice()
func getSubBranch() -> EmptyOffice {
return EmptyOffice()
}

var subBranch: EmptyOffice {
return EmptyOffice()
}
}

How to use a protocol with associative type as return value in Swift?

Not clear what you are trying to achieve, but imho the error stems from the fact that in your addArg function you define a generic type OP which should be typically used in the function's arguments and body.

Instead you return a non generic type trying to force it to be treated as a generic `OP.

A quick fix could be a force cast to OP of your return object:

return OpWithOneArgImpl() as !OP

but I wouldn't recommend it.

In your example your addArg will always return a OpWithOneArgImpl thus it could just be defined as a func addArg(arg: Int) -> OpWithOneArgImpl

Hope this helps.

EDIT:

Probably this is not what you're trying to achieve, but hope it can help
with a clearer explanation of what I intended above.

protocol OpWithOneArg {
typealias ArgType
func addAnotherArg(arg: ArgType)
init() // Must have a init with no argument
}

class OpWithOneArgImpl : OpWithOneArg {
typealias ArgType = Int
func addAnotherArg(arg: Int) {
// ...
}
required init() {
// init implementation
}
}

class OpWithNoArg {
func addArgWithOPType<OP: OpWithOneArg where OP.ArgType == Int>(op: OP.Type, arg: Int) -> OP {
return OP() // Here we use the init
}
}

let foo = OpWithNoArg()
foo.addArgWithOPType(OpWithOneArgImpl.self, arg: 3)

Edit:

Maybe you might investigate the use of generic types:

protocol OpWithOneArg {
typealias ArgType
func addAnotherArg(arg: ArgType)
init() // Must have a init with no argument
}

class OpWithOneArgImpl<T> : OpWithOneArg { // Generic implementation confirming to protocol
typealias ArgType = T
func addAnotherArg(arg: T) {
// ...
}
required init() {
// init implementation
}
}

class OpWithNoArg {
func addArgWithOPType<OP: OpWithOneArg>(op: OP.Type, arg: OP.ArgType) -> OP {
return OP() // Here we use the init
}
}

let foo = OpWithNoArg()

// OpWithOneArgImpl<Int>
foo.addArgWithOPType(OpWithOneArgImpl.self, arg: 3)

// OpWithOneArgImpl<String>
foo.addArgWithOPType(OpWithOneArgImpl.self, arg: "Hello")


Related Topics



Leave a reply



Submit