Template and Type Literals
Quirin Schroll
qs.il.paperinik at gmail.com
Tue May 21 17:38:41 UTC 2024
D has function and delegate literals (usually spelled `x => …` or
`(x) { … }` or `function (T x) {…}`). You know them, you like
them. I don’t have to explain to you how ugly `map`, `filter` and
other ranges would be to use if you had to define and pass the
function/predicate/… by name.
What D lacks is something like that for constructs that aren’t
functions, in particular templates. The idea is that sometimes,
one wants to pass something to a template that isn’t a value,
e.g. a type or a template.
A type literal is something like `struct { … }`, which you could
use as a template argument instead of a named struct. Like with
function literals, there are probably some limitations (e.g.
function literals can’t be recursive), however, using
`typeof(this)` allows one to refer to the otherwise anonymous
struct type, so from the top of my head, I can’t think of one.
More interesting are template literals. There can’t be proper
template literals, though, but specialized ones.
What I mean by “proper template literals” is that there can’t be
`template(T) =>` because what’s going to be after the `=>` arrow?
Templates “return” by eponymous member, but the template has no
name.
Example:
```d
import std.meta;
Instantiate!(alias T => const(T), int)[] xs = [ staticMap!(enum T
=> T.sizeof, byte, short, int, long, struct{ long x, y; }) ];
// const(int)[] xs = [1, 2, 4, 8, 16];
```
For everything D has an abbreviated template syntax, there should
be a template lambda syntax using the same keyword, i.e. `struct
(T) { … }`, `class (T) { … }`, etc.
For aggregates, parentheses around a single type parameter are
obligatory, but for `alias` and `enum`, they should be optional.
Passing a type or template literal is equivalent to passing the
name of a newly defined aggregate type or template.
I intend to limit those constructs to be template arguments only.
If you find use-cases, let me know, but I feel like allowing them
anywhere else makes things a lot more complicated.
Grammar:
```diff
TemplateArgument:
Type
AssignExpression
Symbol
+ AggregateLiteral
+ TemplateLiteral
+
+ AggregateLiteral:
+ struct { AggregateBody }
+ union { AggregateBody }
+ class { AggregateBody }
+ interface { AggregateBody }
+
+ TemplateLiteral:
+ alias TemplateParameters => TemplateArgument
+ alias Identifier => TemplateArgument
+ enum TemplateParameters => TemplateArgument
+ enum Identifier => TemplateArgument
+ struct TemplateParameters { AggregateBody }
+ union TemplateParameters { AggregateBody }
+ class TemplateParameters { AggregateBody }
+ interface TemplateParameters { AggregateBody }
```
Normally, after `TemplateParameters`, there is an optional
`Constraint`, but that doesn’t really make sense here.
More information about the dip.ideas
mailing list