The state of string interpolation

H. S. Teoh hsteoh at
Mon Dec 10 05:43:48 UTC 2018

On Sat, Dec 08, 2018 at 05:17:13PM +0000, o via Digitalmars-d wrote:
> On Saturday, 8 December 2018 at 02:29:10 UTC, Steven Schveighoffer wrote:
> > this compiles:
> > 
> > writeln("a + b = ", a + b);
> > 
> > But this does not:
> > 
> > writeln(AliasSeq!("a + b = ", a + b));
> > 
> > -Steve
> As Paul Backus brought up in a PR, you can use `std.typecons.tuple`s
> instead, to use expressions. Example:
> auto foo = tuple(i"a + b = $(a+b)");

There is more than meets the eye here, that I think we should be aware
of, whether or not it affects the current prospective DIP.

Firstly, there's the compiler's internal representation that Walter
calls a "tuple" (N.B.: not to be confused with std.typecons.tuple) which
is basically a list of "stuff", where "stuff" can be any of: (1) a basic
type with a compile-time known value; (2) a type; (3) an alias to a
Symbol, where a Symbol can be anything that has an identifier associated
with it (basically, an entry in one of the symbol tables used by the
compiler to keep track of identifiers); (4) a function literal aka
lambda, which in my knowledge has some degree of special treatment,
though for the most part it behaves just like (3).

Secondly, there's std.meta.AliasSeq, which is defined as:

	alias AliasSeq(T...) = T;

The `T...` captures a template argument list, which is a "tuple" in
Walter's sense of the word, and gives it an identifier that can be
referred to in code (otherwise, there is no way to refer to the compiler
internal "tuple").  I had thought that AliasSeq ought to be able to
capture all instances of "tuple"s, but apparently I was wrong -- a
"tuple" apparently *can* contain an expression, but expressions cannot
be captured by AliasSeq because of grammatical / syntactical
restrictions placed on template argument lists.  Marler's PR apparently
*does* let interpolated strings capture expressions in a way that
AliasSeq cannot.

Thirdly, there's std.typecons.Tuple, of which std.typecons.tuple is
simply a thin wrapper mainly serving as syntactic sugar for constructing
instances of std.typecons.Tuple.  There's a very important difference
between std.typecons.Tuple and the compiler internal "tuple" in Walter's
sense of the word: std.typecons.Tuple is a *runtime* object that
contains a tuple of *values*.  In contrast, the compiler internal
"tuple" is (obviously) compile-time only.  It basically behaves like an
anonymous struct.  Note that because it is a runtime object, it CANNOT
be used with AST stage compile-time constructs like static if, static
foreach, template expansions, etc.. If you try to access its values in a
static if, you'll get an error. It *is* usable in CTFE, though, if it
can be initialized with compile-time known values.

What we need for this DIP is for interpolated strings to be lowered to
the first kind of tuple, the compiler-internal "tuple" that can capture
AST-accessible "stuff" like string literals and expressions.  I had
thought it was equivalent to AliasSeq, but apparently there's a
discrepancy, and AliasSeq cannot bind expressions which is a no-go. We
cannot use std.typecons.Tuple because it's generally frowned on for the
compiler to depend on Phobos (even though the ^^ operator "cheats" in
that respect -- but to be fair, that was a historical accident predating
the compiler/Phobos clean separation policy). Furthermore,
std.typecons.Tuple cannot be used in static if and other AST stage
constructs, so that's also a no-go.


I don't trust computers, I've spent too long programming to think that they can get anything right. -- James Miller

More information about the Digitalmars-d mailing list