We discovered that by enabling passing functions as generic parameters, we also effectively enabled concepts, a way to specify constraints on parameters, without making them implement any traits.
For example, let's say we already have a Ship struct and a calcDamage function:
Now we want a battle function, which can take any type as long as it has a calcDamage function:
There it is! That where func calcDamage(&T, &T)int specifies that there must be a calcDamage function that takes in two &Ts.
The only existing language today which can accomplish something like this is C++, with its requires requires clause:
As you can see, Vale makes it wonderfully easy to use this approach.
We already use it thoroughly in our standard library. For example, in optutils.vale, we have a function Opt<T>.clone that's only enabled if T also has a clone method:
This can be a lot easier, compared to previous approaches.
For example, in Java or C# or Rust, if we had a pre-existing Ship and calcDamage function, we would have to make an interface (or trait) to describe the bounds and then require all callers to to make their arguments extend that interface (or make an impl, in Rust's case) for every type that they want to supply.
Here's an example in Rust:
If we can't modify the existing type (such as if it's defined by a third-party library) we sometimes need to make a wrapper class (sometimes known as a typeclass or a newtype) which can implement the required interface.
After using this for a few weeks, I had a shocking realization: this is similar in spirit to how we did things in C!
This snippet in Vale...
...would be this in C:
The only real difference is that Vale passes the calcDamage function in at compile-time, and C passes it in at run-time via a function pointer. Aside from that, these approaches are the same.
Note how neither requires that calcDamage be a method of the type, they can be free functions. I think this is a much cleaner approach, that allows us to decouple the type from the functions we use on it.
Thanks for reading, we hope you enjoyed this article! And if you're impressed with our track record and believe in the direction we're heading, please consider sponsoring us on github:
With your support, we can bring easier generics to programmers worldwide!
The Vale Language Project is not just about making Vale, it's also about exploring, discovering, and publishing new programming language mechanisms that enable speed, safety, and ease of use.
The world needs more exploration here! Currently, most programming language research is in:
These are useful, but there is a vast field of possibilities in between, waiting to be explored!
Our aim is to explore that space, discover what it has to offer, and make speed and safety easier than ever before.
In this quest, we've discovered a lot of new techniques:
These techniques have also opened up some new emergent possibilities:
We also gain a lot of inspiration from other languages, and are finding new ways to combine their techniques:
...plus a lot more interesting ideas to explore!
The Vale programming language is only one combination of the features we've found. Our goal is to publish all the techniques we've found, even the ones that couldn't fit in Vale, so that other languages can make strides in this area.
Our medium-term goals:
We aim to publish articles biweekly on all of these topics, and inspire the next generation of fast, safe, and easy programming languages.
If you want to support our work, please consider sponsoring us on GitHub!
With enough sponsorship, we can: