Skip to content

Instantly share code, notes, and snippets.

@vassvik
Last active September 25, 2017 08:14
Show Gist options
  • Save vassvik/9b29687cb88b4683c4e769c15ec871c0 to your computer and use it in GitHub Desktop.
Save vassvik/9b29687cb88b4683c4e769c15ec871c0 to your computer and use it in GitHub Desktop.
Odin polymoprhic procedures and parametric types
// Odin has support for explicit and implicit polymorphic procedures and parametric types
// An explicit polymorphic procedure has the type passed as a parameter,
// while an implicit polymorphic procedure infers the type from the arguments
// a typical use-case for an explicit polymorphic procedure can be found in core/_preload.odin:
new :: proc(T: type) -> ^T {
ptr := cast(^T)alloc(size_of(T), align_of(T));
ptr^ = T{};
return ptr;
}
// and likewise, a similar procedure that uses implicit polymorphism (also from _preload.odin):
new_clone :: proc(data: $T) -> ^T {
ptr := cast(^T)alloc(size_of(T), align_of(T));
ptr^ = data;
return ptr;
}
// note that for implicit polymorphic procedures the first instance of each polymorphic parameter
// in the parameter list have to be marked by a dollar sign
foo :: proc(a: $T, b: $E, c: ^T, d: ^E) -> (T, E) {
// ...
}
// the polymorphic parameters can be pointers, slices, dynamic arrays, maps, or vectors:
stuff_pointer :: proc(a: ^$T) {
}
stuff_slice :: proc(a: []$T) {
}
stuff_dynamic :: proc(a: [dynamic]$T) {
}
stuff_map :: proc(a: map[$T]$E) {
}
stuff_dynamic :: proc(a: [vector 4]$T) {
}
// the polymorphic parameters can also be *specialized*.
// the following example (from _preload.odin) specializes the polymorphic parameter to be a slice,
// while also capturing the base type and the full type
copy :: proc(dst, src: $T/[]$E) -> int {
n := max(0, min(len(dst), len(src)));
if n > 0 do __mem_copy(&dst[0], &src[0], n*size_of(E));
return n;
}
// this can be particularly useful for derived types,
// which would otherwise be distinct types and require a separate overload:
print_string :: proc(a: $T/string) {
fmt.println(a);
}
My_String :: string;
print_string(string("asdasd"));
print_string(My_String("asdasd"));
// print_string(int(2)); // Error: Cannot determine polymorphic type from parameter: `int` to `$T/string`
fmt.println();
// The specialization is also very useful creating procedures that work for any parameters of that struct:
Vec :: struct(T: type, N: int) {
values: [N]T,
}
print_vec :: proc(v: $T/Vec) {
fmt.printf("T = %T, N = %d, values = %v\n", v.values[0], len(v.values), v.values);
}
v1 := Vec(f32, 2){[2]f32{1.0, 2.0}};
v2 := Vec(int, 3){[3]int{3, 2, 1}};
print_vec(v1);
print_vec(v2);
fmt.println();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment