How to Use a Protocol with a Typealias as a Func Parameter

How can I use a protocol with a typealias as a func parameter?

You cannot specialize generic protocol with <>.

Instead, you can:

func method<B: ProtocolB where B.T: ProtocolA>(value: B) {
}

That says, method accepts B where B conforms ProtocolB and its T conforms ProtocolA.

And, in this case, you don't need where B.T: ProtocolA because it's obvious.

func method<B: ProtocolB>(value: B) {
...
}

How to pass generic protocol as function parameter

You must use Datatype as a generic constraint:

func set<T: Datatype>(key: String, type: T ,value: T.dataType)

Note how you also need to change the type of the value parameter to T.dataType, for this to be type safe. That is, the value you pass in must be the same type as the dataType of the type parameter.

AssociatedType in a protocol with typealias

You need a class/struct that conforms to Router, which has an Answer of String:

class StringRouter : Router {
typealias Answer = String
}

let callback: StringRouter.AnswerCallback? = nil

If all you want is such a type alias, you don't need a protocol:

typealias AnswerCallback<T> = (T) -> Void

Using protocol with typealias as a property

Depending on what you are actually trying to do, this can work using type erasure. If you follow the instructions in the link R Menke posted in the comments, you can achieve what you are trying to do. Since your property in TestClass seems to be a let, I'm going to assume you already know the type of DataType at compile time. First you need to setup a type erased Archivable class like so:

class AnyArchiver<T>: Archivable {
private let _save: ((T, String) throws -> Void)
private let _load: (String throws -> T)

init<U: Archivable where U.DataType == T>(_ archiver: U) {
_save = archiver.save
_load = archiver.load
}

func save(data: T, withNewName newName: String) throws {
try _save(data, newName)
}

func load(fromFileName fileName: String) throws -> T {
return try _load(fileName)
}
}

Much like Swift's AnySequence, you'll be able to wrap your Archiver in this class in your TestClass like so:

class TestClass {
let archiver = AnyArchiver(Archiver())
}

Through type inference, Swift will type TestClass' archiver let constant as an AnyArchiver<Int>. Doing it this way will make sure you don't have to create a dozen protocols to define what DataType is like StringArchiver, ArrayArchiver, IntArchiver, etc. Instead, you can opt in to defining your variables with generics like this:

let intArchiver: AnyArchiver<Int>
let stringArchiver: AnyArchiver<String>
let modelArchiver: AnyArchiver<Model>

rather than duplicating code like this:

protocol IntArchivable: Archivable {
func save(data: Int, withNewName newName: String) throws
func load(fromFileName fileName: String) throws -> Int
}
protocol StringArchivable: Archivable {
func save(data: String, withNewName newName: String) throws
func load(fromFileName fileName: String) throws -> String
}
protocol ModelArchivable: Archivable {
func save(data: Model, withNewName newName: String) throws
func load(fromFileName fileName: String) throws -> Model
}

let intArchiver: IntArchivable
let stringArchiver: StringArchivable
let modelArchiver: ModelArchivable

I wrote a post on this that goes into even more detail in case you run into any problems with this approach. I hope this helps!

How can I pass a typealias as a function parameter in Swift?

A type alias is just a synonym for an existing type - it doesn't create a new type, it just create a new name.

That said, if you want to pass a type to a function, you can make it generic, and define it as follows:

func doSomething<T>(type: T.Type) {
println(type)
}

You can invoke it by passing a type - for instance:

doSomething(String.self)

which will print

"Swift.String"

If you define a typealias for String, the output won't change though:

typealias MyString = String
doSomething(MyString.self)

Swift - Make func type explicit (in protocol)

As Action is a typealias and not a type, swift can't differentiate them.

As explained in the documentation:

After a type alias is declared, the aliased name can be used instead of the existing type everywhere in your program. The existing type can be a named type or a compound type. Type aliases do not create new types; they simply allow a name to refer to an existing type.

Edit: My bad, I thought you wanted to differentiate () -> Void and Action.
As far as I know, using a closure is the only way of doing this in swift.

typealias Foo = (Int) -> Void

protocol FooBar {
var foo: Foo { get }
}

class FooBarBaz: FooBar {
var foo: Foo = { intValue in
// ...
}
}

Edit 2: Additional information:

According to the Grammar of a function declaration, the only way of declaring a function is to explicitly provide a parameter-clause, which require listing all parameters between parentheses:

function-declaration → function-head function-name generic-parameter-clauseopt function-signature generic-where-clauseopt function-bodyopt

function-signature → parameter-clause throwsopt function-resultopt

parameter-clause → ( ) | ( parameter-list )

So apparently, it's not possible to declare a function with a type as signature without using a closure.

What is the purpose of declaring typealias for generic type parameter

Declaring a public typealias makes it possible to access the generic type parameter outside of the closed generic type.

For example if you declare a typealias WidgetFoo = Foo<Widget> and keep using WidgetFoo in other places it will be possible to access its T via WidgetFoo.Element(which refers to Widget) whereas you cannot access the generic type parameter E itself. This enables robust and refactoring friendly code - imagine you want to replace Widget with BetterWidget you only have to change one place (the type alias declaration) and no other because WidgetFoo.Element will then refer to BetterWidget.


Example code (provided by @Airspeed Velocity)

struct S<T> { typealias U = T }

typealias TA = S<Int>

let x: TA.T // 'T' is not a member type of 'TA' (aka 'S<Int>')
let y: TA.U

Protocol with generic typealias used by an extension

The extension method parsed() cannot infer that the generic type T is the same type as the immutable that you assign the result of the call to.

You can solve this by supplying the parsed(..) method with the actual parser type as a parameter. You needn't actually make explicit use of this parameter (hence internal name omitted using _), and its sole purpose in this context is to infer the type of the generic T.

// ...

extension Dictionary where Key: StringLiteralConvertible, Value: AnyObject {
func parsed<T: ParserType>(_: T.Type) -> ([T.ParsedObjectType], PaginationContext?) {
let paginatedParser = PaginatedParser<T>()
return try! paginatedParser.parse(self as! AnyObject)
}
}

With this, you needn't explicitly supply the type of result as it can be inferred from the return of parsed(..). Note that I've also added a limitation in the extension for keys that conform to StringLiteralConvertible (String, among others, see language ref.) and for AnyObject values. You shouldn't make extensions more general than they need to be.

Example usage:

let thing2 = [String: AnyObject]()
let result = thing2.parsed(DogParser)

print(result.dynamicType)
/* (Array<Dog>, Optional<PaginationContext>), OK */

Is it possible to have a property containing generic protocol in Swift?

AnotherProtocol has an associated value which must be some type that conforms to MyProtocol. A protocol cannot conform to protocols, including itself, so that type cannot be MyProtocol; it has to be a type conforming to MyProtocol.

var items, then, has to be an array of whatever that type is.

So, let's say you have a type conforming to MyProtocol which defines the associated type to be String:

struct Foo: MyProtocol {
func doSmth(_ value: String) -> String {
value
}
}

Then you can define MyClass as:

class MyClass: AnotherProtocol {
var items: [Foo]
init(_ items: [Foo]) { self.items = items }
}

Of course, if you don't want it to be specific to Foo, you can make it generic with respect to any type T that conforms to MyProtocol and has an associated type of String:

class MyClass<T: MyProtocol>: AnotherProtocol where T.DoSmthValue == String {
var items: [T]
init(_ items: [T]) { self.items = items }
}

let myClass = MyClass([Foo(), Foo(), Foo()])


Related Topics



Leave a reply



Submit