Function arguments may be declared as var, meaning any type is allowed

A different function body is type-checked and compiled for each combination of argument types (specialization)

The comptime expressions are evaluated at specialization-time, so the hasFn test above doesn't exist in the compiled code

The result is a kind of duck-typed meta-programming that is type-checked at specialization-time.

This is really powerful, but there are two things I would like to improve on:

It only allows choosing the function based on the type of the first argument (single dispatch)

The associated functions all live in one namespace, so it's easy to have accidental collisions

Julia has a very similar compilation model (aside from also allowing runtime compilation). But Julia's functions allow multiple dispatch and belong to the namespace they were declared in, rather than the namespaces of all the types they are declared on. This enabled a fantastically composable ecosystem of libraries. Can Zig do that too?

The application author gets to decide in which order to try dispatching, and can add their own dispatch functions at the top of the list to override the choices of other libraries. Like Julia, we probably still want to avoid wanton type piracy but at least we have the tools to fix it if it happens.

Ok, so I lied a little. The code above uses return type inference which hasn't been implemented yet. This code actually works in zig today by adding a second layer of boilerplate to choose the return types. If compiled with zig build-exe test.zig --release-fast -femit-llvm-ir we can open test.ll and confirm that not only was the dispatch compiled away, the math got constant folded away and all that is left is the code to print the answer.

This solves problem 1 (multiple dispatch), but only partially addresses problem 2 (name collisions). We can could go full C and make the top level name something like my_cool_math_lib_add_impls but that still causes problems if we want to import two different versions of the same library.

One neat way to address this would be replace @import("root") with variables that can only be set once, and only at compile-time. Something like: