Compile-time strings

Literals, const and immutable variables in module scope (that aren't initialized in a static constructor), static const and immutable variables in function scope, and manifest constants and enum members, can all be known at compile time. In this section, the focus is specifically on compile-time strings. We're first going to see one more way to initialize them, then we'll see how any compile-time string can be used to generate code.

The import expression

The import expression is quite different from the import declaration that pulls module symbols into the current scope. This expression is used to specify any file name for the compiler to read into memory at compile time. The file will be read as text and treated as a string literal, making it possible to assign it to any variable that can be initialized at compile time.

import std.stdio;
immutable fileData1 = import("myfile1.txt");
enum fileData2 = import("myfile2.txt");
void main() {
  writeln(fileData1);
  writeln(fileData2);
}

Save this as $LEARNINGD/Chapter04/impexp.d. Now create a couple of text files. First up is $LEARNINGD/Chapter04/myfile1.txt with the following content:

Hello from the executable directory!

And then $LEARNINGD/Chapter04/files/txt/myfile2.txt with the following content:

Hello from files/txt/myfile2.txt!

Try to compile this with the following command line:

dmd impexp.d

You should see a couple of errors saying that you need the -Jpath switch. As a security precaution, the compiler requires you to specify one or more paths where it is allowed to search for files named in import expressions. The compiler is also free to disallow any path components from the filename. The path can be absolute or relative to the directory in which the compiler is invoked. For this example, this command line works:

dmd -J. -Jfiles/txt impexp.d

We've passed two paths with -J. The . character represents the compiler's working directory, allowing it to find myfile1.txt. Next we pass files/txt so that myfile2.txt can be found. Running the executable now prints the text from each file.

Although the result of an import expression is a string, it can be cast to an array of any type. Care should be taken when doing so to avoid problems with endianness or alignment. A typical use case is to load a binary file as a ubyte array. I've used this in a little ASCII game project to make sure a default font is always available. For example:

enum defFont = cast(ubyte[])import("deffont.png");

With that, defFont can be passed to a function that knows how to load PNG images from memory. This is a simple case, but imported files often need to be massaged into a different format. In some cases, it may be possible to manipulate the data at compile time using CTFE.

String mixins

The string mixin exists for one purpose and one purpose only: to generate source code from strings. This is a powerful feature that opens the door for all sorts of compile-time configuration without any external tools or a preprocessor. While they really shine when used in conjunction with CTFE and templates, neither feature is needed to demonstrate their functionality. Add the following content to $LEARNINGD/Chapter04/version.txt:

struct AppVersion {
  int major;
  int minor;
  int patch;
}
enum appVersion = AppVersion(1, 0, 1);
enum appVersionString = "1.0.1";

In the same directory, create a file named mixin.d and add the following content:

import std.stdio;
mixin(import("version.txt"));
void main() {
  writeln(appVersion);
  writeln(appVersionString);
}

Compiling with -J. and running will show that version.txt was compiled into the binary. The import expression pulled the file in as a string, then mixin took that string and inserted it into the source code at the point of declaration. After that, the compiler compiled it along with the rest of the module. String mixins often come in handy. They were used to aid in the transition from D1 to D2; they have been used in creating DSLs (Domain-Specific Languages), in compile-time reflection, and more. In every case, they are doing nothing more than what you see here, which is generating source code from strings.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.173.199