Purpose of Typealias

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

Purpose of typealias

  1. typealias is literally for creating an "alias" (i.e. another name) for a type. You are not creating a new type, just another name for an existing type. From the Language Reference:

    Type aliases do not create new types; they simply allow a name to refer to an existing type.

    Therefore, once you declared the typealias, Graph and [String: [String]] now refers to the same type. An extension on Graph is equivalent to an extension on [String: [String]].

  2. For your desired behaviour, you need to create a new type. For a Graph, I think a struct would be appropriate:

    struct Graph {
    ...
    }

    The Graph struct can then contain (or, encapsulate) a private property of type [String: [String]],

    private var adjacencyDictionary: [String: [String]]

    and you should write methods that accesses, and (optionally) mutates the graph. e.g. getNode(withName:), getNeighboursOfNode(withName:), addNode, addEdge etc.

    You should not use a typealias here, because a graph is not a [String: [String]]. For example, the following [String: [String]] is not a (valid) graph:

    ["a": ["b"]]

What is a typealias in Kotlin and how is it being used in this implementation?

It’s often more readable to have dedicated names for function types, such as (Kitty) -> Unit. In the end, a typealias simply gives us a way to define an alias for such a (e.g.) function type which can then be used throughout the code instead of that explicit type as a 1:1 replacement.

In your example the function type (Kitty) -> Unit is being aliased with NewKittiesReceived, which is an argument to the shown function receiveNewKitties. Every variable holding a function (newKittiesReceived in the example) can be invoked with function.invoke(arguments...) or simpler with function(arguments).

There’s only a single situation in which the typealias is used actually: the definition of newKittiesReceived: NewKittiesReceived will be translated to newKittiesReceived: (Kitty) -> Unit.

The docs are found here.

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.

How to create typealias of a function type which refers to a particular function

You cannot assign a function to a typealias.

You can only assign a type.

typealias mathFunctionType = (Int, Int) -> Int

let mathFunction: mathFunctionType = { int1, int2 in
return int1 + int2
}

Why can I type alias functions and use them without casting?

Turns out, this is a misunderstanding that I had about how Go dealt with types, which can be resolved by reading the relevant part of the spec:

http://golang.org/ref/spec#Type_identity

The relevant distinction that I was unaware of was that of named and unnamed types.

Named types are types with a name, such as int, int64, float, string, bool. In addition, any type you create using 'type' is a named type.

Unnamed types are those such as []string, map[string]string, [4]int. They have no name, simply a description corresponding to how they are to be structured.

If you compare two named types, the names must match in order for them to be interchangeable. If you compare a named and an unnamed type, then as long as the underlying representation matches, you're good to go!

e.g. given the following types:

type MyInt int
type MyMap map[int]int
type MySlice []int
type MyFunc func(int)

the following is invalid:

var i int = 2
var i2 MyInt = 4
i = i2 //both named (int and MyInt) and names don't match, so invalid

the following is fine:

is := make([]int)
m := make(map[int]int)
f := func(i int){}

//OK: comparing named and unnamed type, and underlying representation
//is the same:
func doSlice(input MySlice){...}
doSlice(is)

func doMap(input MyMap){...}
doMap(m)

func doFunc(input MyFunc){...}
doFunc(f)

I'm a bit gutted I didn't know that sooner, so I hope that clarifies the type lark a little for someone else! And means much less casting than I at first thought :)

What is the difference between Type Alias and Type Definition in Go?

type A = string creates an alias for string. Whenever you use A in your code, it works just like string. So for example, you can't define methods on it.

type A string defines a new type, which has the same representation as string. You can convert between an A and string at zero cost (because they are the same), but you can define methods on your new type, and reflection will know about the type A.

For example (on the playground)

package main

import (
"fmt"
)

type A = string
type B string

func main() {
var a A = "hello"
var b B = "hello"
fmt.Printf("a is %T\nb is %T\n", a, b)
}

Output:

a is string
b is main.B

Is it a good idea to use a type alias name in python and then declare that as a variable?

No, decks is not a type alias. It is a type-annotation. According to PEP-484:

Type aliases are defined by simple variable assignments.

Or according to the typing documentation:

A type alias is defined by assigning the type to the alias.

So assigning to a variable anything that would be a valid type annotation is a type alias:

decks = Dict[str, Any]

This way decks would be a type alias.

But when you use the colon, you are annotating that variable, not creating a type alias:

decks: Dict[str, Any]

According to Python's type annotation conventions, you've simply annotated the decks attribute for DeckManager instances to have type Dict[str, Any].

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