Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compile time evaluation

Tags:

compile-time

d

If I write

enum chars = digits ~ uppercase;

will the string be concatenated at compile time? I'm assuming it will. If I replace it with a string literal or a CTFE function I can't measure any significant performance differences (even calling it a hundred million times). I do get a difference if I replace enum with const. I've been told it's inefficient to write it like this. I thought it was kind of convenient and I don't see the inefficiency. (BTW, the line is in a function that's called recursively).

The full code (converting to a numeral system with a different base)

import std.string;

string toBase(long n, int b) 
in {
    assert(2 <= b && b <= 35);
} body {
    static string sign;
    if (n < 0) {
        n *= -1;
        sign = "-";
    }
    enum chars = digits ~ uppercase;
    size_t r = cast(size_t)(n % b);
    if (n == r) {
        return sign ~ chars[r];
    }
    return toBase((n - r) / b, b) ~ chars[r];
}

Edit: updated code, in response to comments, not relevant to the question

string toBase(long n, int b) 
in {
    assert(2 <= b && b <= 35);
} body {
    enum chars = digits ~ uppercase;
    long r = n % b;
    char c = chars[cast(size_t) abs(r)];
    if (n == r) {
        return (n < 0 ? "-" : "") ~ c;
    }
    return toBase((n - r) / b, b) ~ c;
}
like image 730
fwend Avatar asked Jul 03 '11 12:07

fwend


2 Answers

enum instantiations like that are always evaluated at compile-time (and throw compile errors when the evaluation is impossible at compile time)

so the concatenation is done at compile-time and an immutable version is stored in the code and referenced at runtime

like image 179
ratchet freak Avatar answered Nov 18 '22 12:11

ratchet freak


One way to check for yourself whether the string is concatenated at compile time is to compile the code and examine the object file. Assuming your file is called test.d:

dmd -c test.d
objdump test.o | grep -C3 "012345"

...should produce something like:

Contents of section .rodata:
 0000 2d000000 00000000 00000000 00000000  -...............
 0010 01000000 00000000 00000000 00000000  ................
 0020 30313233 34353637 38394142 43444546  0123456789ABCDEF
 0030 4748494a 4b4c4d4e 4f505152 53545556  GHIJKLMNOPQRSTUV
 0040 5758595a 00000000 00000000 00000000  WXYZ............
 0050 24000000 00000000 20000000 00000000  $....... .......

(This is on Linux; on other platforms, you'll need different tools to inspect the object file.)

If you change your enum to const or string, you will (probably) get no output: there will be no concatenated string for grep to find.

But the compiler may concatenate strings at compile-time even when enum is not used. Consider this program:

 import std.stdio;

 enum a = "Aaaa";
 enum b = "Bbbb";
 enum c = "Cccc";

 void main() 
 {
   enum   x = a ~ b;
   const  y = b ~ a;
   string z = a ~ c;
   writeln(x, y, z);
 }

Now, compile it, and examine the object file:

% dmd -c test2.d && objdump -s test2.o | egrep "(Aaaa|Bbbb)"
 0000 42626262 41616161 00000000 00000000  BbbbAaaa........
 0020 41616161 43636363 00000000 00000000  AaaaCccc........
 0040 41616161 42626262 00000000 00000000  AaaaBbbb........

We see that x, y and z are all static literals. (Mark a, b and c as const instead of enum, and you may see different behaviour.) So, while enum is a guarantee of compile-time evaluation, the absence of enum doesn't prevent compile-time evaluation.

like image 21
gmfawcett Avatar answered Nov 18 '22 11:11

gmfawcett