Last active
December 5, 2024 15:35
-
-
Save vassvik/9b29687cb88b4683c4e769c15ec871c0 to your computer and use it in GitHub Desktop.
Odin polymoprhic procedures and parametric types
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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