Type parameters

We have already discussed the typing system in haXe, but now, we are going to see the Type parameters. You may have already seen them in some languages, maybe under the name of Generics.

We will now see:

  • The usage of Type parameters
  • Using Type parameters with already created types
  • Creating a type that makes use of them
  • Creating an example

Let's continue discovering the typing system!

Usage of Type parameters

So far, you have only created functions that took some parameters with a defined type and returned a value with a defined type. You have always decided what these types were when creating your functions.

With Type parameters, it is possible to let the person use a class and decide what types will be used by some of its functions.

You may wonder why this is useful, and indeed, we have already used Type parameters in this book; remember how we said we were going to create an "Array of String"? Well, we have been using Type parameters at this moment.

In fact, Type parameters are like function parameters, but they are given at the class level and instead of waiting for a value, they are waiting for a type.

Type parameters can be used for several things, but most of the time, they are used inside containers such as array or list. This way, you can have an array of fully typed elements because you can only add elements of this type and therefore, we can be sure that you only get elements of this type from the array.

Creating a parameterized class

A class is said to be parameterized when it makes uses of Type parameters. Therefore, for example, the Array class is a parameterized class.

Now, let's see how a part of it may have been written. In this example, I will only talk about the push and shift methods. The first one allows you to add an object into the array while the last one allows you to remove and retrieve the first object in the array.

Please note that this is not the exact code for the Array class.

class Array<T>
{
function new()
{
//Do things here
}
function push(obj : T)
{
//Do things
}
function shift() : T
{
//Do things
}
}

There are two very important points to notice.

The first one is on the first line, where between the< and> symbol lies an indication telling that our class is parameterized and wants one type to be designed by the T letter. In this class, T is said to be an abstract type. Note that you could have used any name, but by convention, we generally use letters starting from T for abstract types.

The other point is that, although the constructor will be called by specifying the parameter type (new Array<String> for example), you do not have to write it in the constructor.

Also, note how in your code you may use T, as if it was an actual type.

The only drawback here is that, as T can be any type, you cannot call any method nor do anything that needs to know the type of the value. This is where constraints will be interesting, and that is what we will discuss now.

Constraint parameters

You can put some constraints on your type parameters. Indeed, you can specify any number of types that the type parameters must either implement or extend. Look at the following example:

class Fridge<T: (Fruit, Eatable)>
{
//...
}

In this example, the Fridge class expects a type that implements or extends both the Fruit and Eatable types. Note that when you want to impose several constraints on the same abstract type, you have to enclose all of these in parentheses.

Doing so has the following two advantages:

  1. As the compiler knows what types your value has, you will be able to use it as if it was typed as being a Fruit and an Eatable.
  2. You can limit the types of values you will accept: for example here, our fridge will only accept fruits that can be eaten.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.194.106