As part of my series of templates
I have done a a full instantiation of Iota!(1,5).
(By hand!)
And here is the result:
Iota!(1,5)
{
{
alias Iota = Seq!(1, Iota!(1 + 1, 5));
}
Seq!(1, Iota!(1 + 1, 5))
{
alias Seq = (1, Iota!(1 + 1, 5));
Iota!(1 + 1, 5) => Iota!(2, 5)
{
alias Iota = Seq!(2, Iota!(2 +1, 5));
}
Seq!(2, Iota(2 + 1, 5))
{
alias seq = (2, Iota!(2 + 1, 5))
Iota!(2 + 1, 5) => Iota!(3, 5)
{
alias Iota = Seq!(3, Iota!(3 +1, 5));
}
Seq!(3, Iota!(3 + 1, 5))
{
alias Seq = (3, Iota!(3 + 1, 5));
Iota!(3 + 1, 5) => Iota!(4, 5)
{
alias Iota = Seq!(4, Iota!(4 +1, 5));
Seq!(4, Iota!(4 + 1, 5))
{
alias seq = (4, Iota!(4 + 1, 5));
Iota!(4 + 1, 5) => Iota!(5, 5)
{
{
alias Iota = Seq!();
{ Seq!() => () }.Seq => ()
}
}.Iota => Seq!()
}.Seq => (4, Seq!())
}.Iota => (3, Seq!(4, Seq!())
}.Seq => (3, Seq!(4, Seq())))
}.Seq => (2, (Seq!(3, Seq!(4, Seq!()))))
}.Seq => (1, Seq!(2, Seq!(3, Seq(4, Seq!())))))
}.Iota => (1, Seq!(2, Seq!3, Seq!4, Seq!()))))))
Because it has been done manually there are probably some bugs.
Can you find them all?
Iota should be this:
`tuple(x .. y)` (assuming 1st-class tuples existed), or in the current language: `AliasSeq!(x .. y)`, which is syntactically invalid, but something like this really should exist.
Your example expansion above looks kinda broken, but it makes the point... I feel like D is currently awakening to a similar reality as the C++ dark-ages period in the mid 00's, where templates were 'discovered', books were written (by popular authors), and the worst C++ code and patterns ever written came into existence. The reaction for many of us at that time (especially in video games/embedded systems) was to ban C++ completely and revert to C for a decade until such a later time that we could be trusted again.
This is essentially D's manifestation of the same negligence, and I think it's time to own it and move forward.
I think there are a few obvious solutions:
1. My `...` operator DIP, map/reduce patterns are extremely common and responsible for much/most explosive template bloat
2. Recognise that templates are NOT FOR EXECUTING CODE; templates are for parameterisation of definitions.
There is a painfully obvious tool for executing code; functions, made up of a series of statements.
The rule of least-surprise should surely dictate that when people want to perform calculations or generate a result, they should use a function.
Sadly, functions don't work in static contexts like with types or aliases... so in D, meta with such results can only be written awkwardly with templates.
There has been discussion of type functions on and off for ages, and Stefan has recently demonstrated some concrete progress on this front... I think that's the way forward. It is the path that will lead us from the dark instantiation-bloat forest that D finds itself in today. It will be clearer, saner, and faster. A new D user will find a type function intuitive, and will never have to poison their mind with awkward FP-style recursive template expansions with weird edges and considerations.