Ceylon language
David Nadlinger
see at klickverbot.at
Sat Apr 16 01:46:55 PDT 2011
On 4/15/11 8:19 PM, Andrej Mitrovic wrote:
> […] My biggest issue is that
> I can't modify variables at compile time. I wish there was some
> special CTFE int type which is only visible at compile-time and which
> we can use however we want. That way I could keep count of things, for
> example I could generate a list of indexes that can then be mixed in
> as a string.
> […]
> I dunno, CTFE overall seems like a buggy thing where I have to guesswhether something will work or not. It's very stress-inducing.
Correct me if I'm wrong, but might it be that you are conflating
templates and CTFE, which are – although they are both used for
metaprogramming – two entirely different concepts?
Maybe it helps to think of calling a function at compile time as a gate
into a parallel universe. In this other world, you can modify variables,
call functions, etc. as you please, just as if you were executing code
at runtime (well, inside the more or less implementation-defined
boundaries of CTFE). The only restriction is that you can only return a
single value through the gate, there is no other way to influence the
»compiler« universe from inside the functions you call. More
specifically, there is no way to manipulate types in the compiler
universe – although you can instantiate templates in CTFE functions just
like normal, you will never be able to »return« them back to the outside
world. Also, be aware of the fact that a CTFE function can just work on
_values_, like every other runtime function, not on types.
So much for CTFE. Templates, on the other hand, are basically just named
scopes with a few extra features which happen to make a Turing complete
language. As such, there will never be something like a runtime variable
modifiable at compile time in templates, as you asked (at least I hope
so). The interesting thing about templates is that they allow you to
work with types themselves. Due to the absence of mutable state, you are
generally limited to functional techniques, though, which can be
uncomfortably similar to the proverbial Turing tarpit in some cases
(although it's surprising how easy it is to write certain algorithms in
a functional manner once you got the hang of it).
However, there are ways to combine templates and CTFE to your advantage.
Without any concrete question, it's obviously hard to give a good
suggestion, but an example would be to use template functions called at
compile time to produce string mixins:
---
string generateCode(T...)() {
string code;
[… construct a string containing some declarations …]
return code;
}
template Foo(T...) {
alias DoSomethingWithATypeTuple!(T) U;
mixin(generateCode(U));
}
---
You can also shorten this by using delegate literals:
---
template Foo(T...) {
alias DoSomethingWithATypeTuple!(T) U;
mixin({
[…]
return "<some code generated while having access to T and U>";
}());
}
---
Another small template metaprogramming example showing a way to process
a list of types without needing mutable state. Specifically, it aliases
a new type tuple to Result which doesn't contain any items where
Exp.numerator is 0 (you can do the same with eponymous templates).
TypeTuples are automatically flattened, which allows for a concise
implementation here.
---
template Process(T...) {
static if (T.length == 0) {
alias TypeTuple!() Result;
} else {
alias T[0] A;
static if (A.Exp.numerator == 0) {
alias Process!(T[1..$]).Result Result;
} else {
alias TypeTuple!(A, Process!(T[1..$]).Result) Result;
}
}
}
---
As for constructing lists of indices and then generating code of them:
If you need to work on types for generating the list, you could e.g. use
some recursive template to construct a type tuple of integer literals
(that name really doesn't fit well), and then process it via CTFE to
generate code to be mixed in – or whatever you need in your specific
case. Feel free to ask about any specific problems in d.D.learn.
David
More information about the Digitalmars-d
mailing list