I think the answer is fundamentally: giving the compiler a lot of information at compile time so it can optimize the generated code for the runtime, be it explicitly by type annotations or implicitly by type inference. If the compiler is sure a variable will be a 32 bits int, it can translate to the same instructions that any language that is not dynamic could.
What Julia language does is give programmers powerful tools to encode types, behaviors and even code manipulation/generation tools that can be fully resolved in compile time, while still having a fully dynamic runtime.
Yeah but it's not statically typed. Let's say you have a machine learning algorithm and you'd like to change your algorithm to have a complex-valued weights instead of float valued weights. How do you do that in a statically typed language?
Let's say you want to test the numerical performance of the fast Fourier transform using an alternative datatype to IEEE 754 (for example bfloat8). How do you do that?
Another application:. I wanted to play with galois fields for reed Solomon encoding. One key step is LU decomposition to recover missing data. Well, as it turns out built-in matrix solving algorithm in Julia is general, (though it does kick over to BLAS for floats), so my galois field type was plug and play, I didn't have to write a custom solver.
> How do you do that in a statically typed language?
You can do that only if the interface for both types is identical or compatible. They should offer at least a common subset of the same operations. Hence, "generics" is the answer to your question.
I understand your feeling. But my impression is that this kind of "black magic" isn't always the best. With generics and static typing, if it compiles, you'll know it will work. With "type inference" you need to test it at runtime. It may compile with near-native performance, or it may not. And maybe a small change in your source code will turn near-native performance to dismal performance.
Not really. Values have types, unsurprisingly, but variables don't.
However, if the compiler can deduce the type at compile time, it will dispatch to the accordingly optimised function. (And type stable code helps doing that).
What Julia language does is give programmers powerful tools to encode types, behaviors and even code manipulation/generation tools that can be fully resolved in compile time, while still having a fully dynamic runtime.