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:
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:
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.