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
Invalid Update: Invalid Number of Rows in Section 1
Do Protocols Have an Effect on The Retain Count
Switch Statement Where Value Is Int But Case Can Contain Array
Swiftui Change on Multilevel Children Published Object Change
Public Default Init in Protocol
Swiftui - How to Change The Button's Image on Click
Upload Multiple Images to Ftp Server in iOS
Swiftui Section from Attribute of a Struct
Support Arkit in Lower End Devices
Create Record Only If Parent Exists in Vapor Using Fluent
Rxswift + Mvvm + Coordinator Pattern, How to Wait for Coordinator Result Sequentially
Tintcolor Not Changing for UIbarbuttonitem for .Normal Stage in Case of iOS 13.2
Inmemory Realm Threading in Swift
Secidentity + Force Cast Violation: Force Casts Should Be Avoided. (Force_Cast)
Show Status Bar Only for iPhone X