Skip to content

Instantly share code, notes, and snippets.

@kiljacken
Last active August 29, 2015 14:26
Show Gist options
  • Save kiljacken/55f7c4e429bb16c1f5bf to your computer and use it in GitHub Desktop.
Save kiljacken/55f7c4e429bb16c1f5bf to your computer and use it in GitHub Desktop.

Generics

Generics provide a method for creating functions and composite types that work across a wide range (read: all other) of types.

An example of a type definition using generics is the Option type:

type Option<T> enum {
	None,
	Some(T)
};

The definition tells us that the type Option takes a type parameter T, which after declaration can be used as if it was just a plain type. To declare an instance of the type you can explicitly pass a type parameter, or in most cases, let the compiler infer the type for you:

a: int = 0;
x := Option::None<int>()
y := Option::Some(a);

The other use case for generics is for defining functions that act on many types. An example of this could be a type-agnostic allocation function:

func alloc<T>(): ^T {
    ptr := C::malloc(sizeof(T));
    ... // Check allocation success
    return ^T(ptr);
}

As with the Option type the definition tells us that alloc takes a type parameter T. The names of type parameters have the same limits as any other identifier, so T could've been named TypeToAllocate and the example would've worked just as well. Invoking the functions follow the same semantics as with using a generic type. It can either be done explicitly, or by letting the compiler infer the type:

x := alloc<SomeLargeStruct>();
y: ^SomeLargeStruct = alloc();

Multiple type parameters

When using generics you are not limited to one type parameter. This allows for even more complicated, but often even more useful, constructs. An example of using more than one type parameter could be a map:

type Map<Key, Value> struct {
    ...
};

The example works exactly like you might expect. Both type parameters can be used as if they were types within the body of the struct.

Methods on generic types

Continuing from the previous example you might notice something missing. How are you supposed to actually use the structure without copy-pasting code everywhere? Usually you would implement a method on the structure, but would that work here? Luckily methods can be declared on generic types aswell with almost no syntactical overhead. An example of defining a method an our Map is as follows:

func (Map<Key, Value>) Get(key: Key): Value {
    ...
}

When defining a method on a generic type, the type parameters given to the type carry over to the function that's being implemented. Thus the Get function has knowledge of Maps two type parameters, Key and Value, and can use them just like any other type. Note that the names do not have to match with the names used to define the type, so Map<Key, Value> might as well have been written Map<K, V> if the author felt that more fitting.

Type restrictions

It is not always the case that a generic function/type wishes to work with all types. To allow for the creation of functions/types like this we use the concept of type restrictions. A type restriction is, as the name suggests, a way to lock down the types that can be used with a generic type/function. To ease explaining we start with an example:

type Vector3<T: Number> struct {
    x: T, y: T, z: T
};

Again we have a type with a type parameter T, this time the parameter is followed by a colon and an identifier. This identifier, in our case Number, is the name of an interface. It means that, T must implement the interface Number to be usable in a Vector3.

Just like you can use multiple type parameters, you can also use multiple type restrictions. An example of this is the following:

type HashMapWithIteratorKeysForSomeReason<Key: Hash & Iterator, Value> struct {
    ...
};

This means that Key has to both interfaces, Hash and Iterator. Again, the only limit to how many restrictions you can use is your imagination. And common sense.

@felixangell
Copy link

Lgtm 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment