Need Clarification on Typealias Syntax in Swift

Need clarification on typealias syntax in Swift

In a protocol, typealias declares an associated type. Classes and structures that conform to this protocol must have a typealias directive that declares the type to something concrete.

Yes, it means that Generator must conform to GeneratorType in any implementation of the SequenceType protocol.

Use of typealias syntax within protocols in the Swift standard library

Take a look at this answer. Use of a colon shows inheritance, use of an equals sign shows assignment.

In my understanding this means the following:

typealias X // defines associated type X for subclasses to override
typealias X: Y // defines associated type X and requires that it conform to Y
typealias X = Z // defines associated type X with a default of type Z
typealias X: Y = Z // defines associated type X with a default of type Z and requires that any overrides conform to Y

My interpretation seems to be supported by this article on Swift generics:

An associated type is declared by a protocol using the typealias
keyword. It normally set by an item that conforms to that protocol,
although you can supply a default. Like type parameters, an
associated type can be used as a token when building generic type
rules.

The use of the keyword typealias can be misleading for defining associated types and may be replaced by associatedtype in the future.

When to use typealias?

Actually, there is no doubt that creating a typealias for -let's say- String: typealias MyString = String wouldn't be that useful, (I would also assume that declaring a typealias for Dictionary with specific key/value type: typealias CustomDict = Dictionary<String, Int> might not be that useful to you.

However, when it comes to work with compound types you would definitely notice the benefits of type aliasing.

Example:

Consider that you are implementing manager which repeatedly work with closures with many parameters in its functions:

class MyManager {
//...

func foo(success: (_ data: Data, _ message: String, _ status: Int, _ isEnabled: Bool) -> (), failure: (_ error: Error, _ message: String, _ workaround: AnyObject) -> ()) {
if isSuccess {
success(..., ..., ..., ...)
} else {
failure(..., ..., ...)
}
}

func bar(success: (_ data: Data, _ message: String, _ status: Int, _ isEnabled: Bool) -> (), failure: (_ error: Error, _ message: String, _ workaround: AnyObject) -> ()) {
if isSuccess {
success(..., ..., ..., ...)
} else {
failure(..., ..., ...)
}
}

// ...
}

As you can see, the methods signatures looks really tedious! both of the methods take success and failure parameters, each one of them are closures with arguments; Also, for implementing similar functions, it is not that logical to keep copy-paste the parameters.

Implementing typealias for such a case would be so appropriate:

class MyManager {
//...

typealias Success = (_ data: Data, _ message: String, _ status: Int, _ isEnabled: Bool) -> ()
typealias Failure = (_ error: Error, _ message: String, _ workaround: AnyObject) -> ()

func foo(success: Success, failure: Failure) {
if isSuccess {
success(..., ..., ..., ...)
} else {
failure(..., ..., ...)
}
}

func bar(success: Success, failure: Failure) {
if isSuccess {
success(..., ..., ..., ...)
} else {
failure(..., ..., ...)
}
}

// ...
}

Thus it would be more expressive and readable.




Furthermore, you might want to check a medium story I posted about it.

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

Swift typealias error

This is not a correct function type declaration:

typealias LoginHandler = (_ msg: String) -› Void

You are using the wrong "greater than" symbol (unicode hex 203A).

Your code should look like this:

typealias LoginHandler = (_ msg: String) -> Void

Notice that difference in the second character making up the "arrow operator" (unicode hex 003E).

Swift: Function syntax with closure and type alias

This code:

activeMembers { (members) in
for name in members {
print("\(name) is active")
}
}

is a call to activeMembers(completion:)`. When fully de-sugared, it looks like this:

activeMembers(completion: { (members: [Member]) -> Void in
for name in members {
print("\(name) is active")
}
})

Since you haven't given us the definition of the arrayClosure typealias (which should be capitalized like other type names, btw, ArrayClosure), I've had to assume that members has type [Member].

The closure (the code starting between the { }) is just a value, and that value is passed as an argument to the completion parameter of activeMembers. The implmentation of the activeMembers function is then taking the completion closure, and calling it. It calls it, giving the partyMembers value as an argument to its sole parameter.

Since completion is referring to your for-loop-containing closure, calling it will run the code inside your closure. The partyMembers argument is now the value of the members parameter, which is then looped over and printed.

You can better understand this by tracing through what's going on:

var partyMembers = ["Harrison", "Steven", "Bob the Noob"]
typealias Member = String
typealias arrayClosure = ([Member]) -> Void

func activeMembers(completion: arrayClosure) {
print("About to call completion")
print("The value of partyMembers is: \(partyMembers)")
completion(partyMembers)
print("About to return from activeMembers(completion:)")
}

print("1. About to create closure")
let closure: arrayClosure = { (members: [Member]) -> Void in
print("4. Entered closure, about to loop over the members.")
print("5. The value of the members parameter is: \(members)")
for name in members {
print("\(name) is active")
}
print("6. Finished looping")
print("7. About to return from the closure")
}
print("2. Closure created")

print("3. About to call activeMembers(completion:)")
activeMembers(completion: closure)
print("8. Finished call to activeMembers(completion:)")

Generic typealias in Swift

Generic typealias can be used since Swift 3.0. This should work for you:

typealias Parser<A> = (String) -> [(A, String)]

Here is the full documentation: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/typealias-declaration

Usage (from @Calin Drule comment):

func parse<A>(stringToParse: String, parser: Parser) 

Use TypeAlias in other class

You need to define the TypeAlias as public and that too outside the class.

The other option is to define protocol and inherit to any class.



Related Topics



Leave a reply



Submit