# 1.1 Polymorphism

Almost everything (except variables) in Felix can be polymorphic, that is, parametrised by a list of types. Here is a simple example:

fun diag[T,U] (x:T, y:U)=> y,x; a := 1,"Hi"; println$ a, diag a, diag (diag a);

C bindings can be polymorphic too:

type vector[T] = "::std::vector<?1>"; proc push_back[T]: vector[T] * T = "$1.push_back($2)";

In the C code {?1}, {?2} represent the first and second type variables.

## 1.1.1 Overloading

Polymorphic functions and non-polymorphic function can be overloaded. Overload resolution proceeds by a similar algorithm to C++.

Felix first finds all the candidates. It then proceeds to compare each signature with each other signature. If one is a proper specialisation of another, the more general case is thrown out. An ambiguity exists if this process leaves more than one candidate.

fun f[T,V] (x:T, y:V)=>y,x; //1 fun f[T] (x:T, y:T)=>y,x; //2 fun f[A,B,C] (x: A * B, y : B *C) => y,x; //3

Here, 2 and 3 are more specialised than 1, however neither is more specialised than the other.

If the call is to a higher order function and the call applies to several arguments in turn, all the available arguments are used in an attempt to remove an ambiguity.

# 1.2 Advanced Type Calculus

Felix type system has several advanced features.

## 1.2.1 Type functions

In Felix you can specify a function which accepts and returns types:

typedef fun diag1 (x:TYPE) : TYPE => x * x; var b: diag1 int = 1,2; // OK

Here the name `TYPE`

is a meta-type or kind representing all types.

A type function is similar to a type index, however functions cannot be overloaded based on calculated types, unless the applications are resolved before overloading is performed.

```
typedef diag2[T] = T * T;
```

is similar to the type function `diag1`

, but `diag2`

is a polymorphic
type, which is not quite the same. Polymorphic type allow overloading,
and more generally unification, to deduce the index type. This cannot
be done for type functions. But type functions are more general because
they can be named "unapplied" and later applied. And, they can be
anonymous too: type lambdas.

The syntax for type functions is the same as for ordinary functions. Type functions can also be overloaded against each other.

## 1.2.2 Type matches

Similar to ordinary matches, Felix has type matches:

typedef T = int; val x : typematch T with | int => int * int | _ => long endmatch = 1,2 ;

A contrived example, but see the next section for a real use!

## 1.2.3 Type Calculus: examples

Consider the C integral promotion rules. How would we represent this in Felix?

With a type function and match of course! This is from library file int.flx:

typedef fun integral_promotion: TYPE -> TYPE = | tiny => int | utiny => int | short => int | ushort => int | int => int | uint => uint | long => long | ulong => ulong | vlong => vlong | uvlong => uvlong ;

Note here the same short hand as for function is used, the functional form is equivalent to a function containing a match on its only argument.

The type function `integral_promotion`

defines how each C type is promoted
according to ISO C rules.

Now why would we want that? Well consider, we would like to write this code:

fun add[T in ints, U in ints]: T * U -> arithmax (T,U) = "$1+$2";

which can add up any Felix integers the same way as C does, arithmetic promotions and all .. but what is the return type? It is the largest of the two argument types. But how can we calculate that?

Here's the answer: arithmax.flx

This file is generated by the configure script for Felix because the rule is actually platform dependent!

You can see here, we have used the previously discussed `integral_promotion`

function to reduce the number of cases in the `typematch`

by removing
the smaller types {tiny, utiny, short, ushort} .. although the main reason
is that this is how ISO C specifies the calculation be done.