www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - At compile time

reply bearophile <bearophileHUGS lycos.com> writes:
D2 is now able to execute math functions (sin, cos, sqrt, etc) at compile time.

This little C++ program compiles correctly with G++:

// C++ code
#include <math.h>
#include <stdio.h>

struct V3 {
    double x, y, z;
    V3(const double a, const double b, const double c) : x(a), y(b), z(c) {}
    V3 operator*(const double d) const { return V3(x * d, y * d, z * d); }
    V3 norm() const { return *this * (1.0 / sqrt(magsqr())); }
    double dot(const V3 &v) const { return x * v.x+y * v.y + z * v.z; }
    double magsqr() const { return dot(*this); }
};

const V3 v(V3(-0.5, -0.65, 0.9).norm());

int main() {
    printf("%f %f %f\n", v.x, v.y, v.z);
    return 0;
}


But similar D2 program produces, with DMD v.2.031:
test.d(12): Error: non-constant expression (V3(1,2,3)).norm()

// D2 code
import std.math, std.c.stdio;

struct V3 {
    double x, y, z;
    V3 opMul(double d) { return V3(x * d, y * d, z * d); }
    V3 norm() { return this * (1.0 / sqrt(this.magsqr())); }
    double dot(ref V3 v) { return x * v.x+y * v.y + z * v.z; }
    double magsqr() { return dot(this); }
}

const V3 v = V3(1.0, 2.0, 3.0).norm();

int main() {
    printf("%f %f %f\n", v.x, v.y, v.z);
    return 0;
}

Do you know why?
Can the D2 compiler modified/improved to allow this?

Bye and thank you,
bearophile
Aug 04 2009
next sibling parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Tue, Aug 4, 2009 at 7:57 PM, bearophile<bearophileHUGS lycos.com> wrote:
 D2 is now able to execute math functions (sin, cos, sqrt, etc) at compile=
time.
 This little C++ program compiles correctly with G++:

 // C++ code
 #include <math.h>
 #include <stdio.h>

 struct V3 {
 =A0 =A0double x, y, z;
 =A0 =A0V3(const double a, const double b, const double c) : x(a), y(b), z=
(c) {}
 =A0 =A0V3 operator*(const double d) const { return V3(x * d, y * d, z * d=
); }
 =A0 =A0V3 norm() const { return *this * (1.0 / sqrt(magsqr())); }
 =A0 =A0double dot(const V3 &v) const { return x * v.x+y * v.y + z * v.z; =
}
 =A0 =A0double magsqr() const { return dot(*this); }
 };

 const V3 v(V3(-0.5, -0.65, 0.9).norm());

 int main() {
 =A0 =A0printf("%f %f %f\n", v.x, v.y, v.z);
 =A0 =A0return 0;
 }


 But similar D2 program produces, with DMD v.2.031:
 test.d(12): Error: non-constant expression (V3(1,2,3)).norm()

 // D2 code
 import std.math, std.c.stdio;

 struct V3 {
 =A0 =A0double x, y, z;
 =A0 =A0V3 opMul(double d) { return V3(x * d, y * d, z * d); }
 =A0 =A0V3 norm() { return this * (1.0 / sqrt(this.magsqr())); }
 =A0 =A0double dot(ref V3 v) { return x * v.x+y * v.y + z * v.z; }
 =A0 =A0double magsqr() { return dot(this); }
 }

 const V3 v =3D V3(1.0, 2.0, 3.0).norm();

 int main() {
 =A0 =A0printf("%f %f %f\n", v.x, v.y, v.z);
 =A0 =A0return 0;
 }

 Do you know why?
I don't think you can call struct methods at compile-time. Kind of lame, I know. Try making norm a free function.
 Can the D2 compiler modified/improved to allow this?
It sure would be nice.
Aug 04 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Jarrett Billingsley:
 I don't think you can call struct methods at compile-time.  Kind of
 lame, I know.  Try making norm a free function.
I see. It's a significant limitation, that curiously G++ doesn't share. I have tried to follow your suggestion, but so far with not too much luck, even essentially pulling out all methods of that struct :-) Thank you, bye, bearophile
Aug 04 2009
parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Tue, Aug 4, 2009 at 10:13 PM, bearophile<bearophileHUGS lycos.com> wrote=
:
 Jarrett Billingsley:
 I don't think you can call struct methods at compile-time. =A0Kind of
 lame, I know. =A0Try making norm a free function.
I see. It's a significant limitation, that curiously G++ doesn't share.
I don't think your C++ code is doing what you think it's doing. I'm pretty sure the C++ code: const V3 v(V3(-0.5, -0.65, 0.9).norm()); is equivalent to the following D code: const V3 v; static this() { v =3D V3(-0.5, -0.65, 0.9).norm(); } C++ has static initialization that occurs before main() too. It's just.. hidden.
Aug 04 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
Jarrett Billingsley:
C++ has static initialization that occurs before main() too.  It's just..
hidden.<
I see. I have to learn more about C++. Thank you. ------------------ Lars T. Kyllingstad:
This is good news! The restrictions you are referring to, are they any of the
ones documented here:
http://www.digitalmars.com/d/2.0/function.html#interpretation <
That list has a point regarding what I was trying to do:
4. the function may not be a non-static member, i.e. it may not have a this
pointer<
It's true regarding stucts used as values too, and not just classes... Bye, bearophile
Aug 05 2009
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
bearophile escribió:
 Jarrett Billingsley:
 C++ has static initialization that occurs before main() too.  It's just..
hidden.<
I see. I have to learn more about C++. Thank you. ------------------ Lars T. Kyllingstad:
 This is good news! The restrictions you are referring to, are they any of the
ones documented here:
http://www.digitalmars.com/d/2.0/function.html#interpretation <
That list has a point regarding what I was trying to do:
 4. the function may not be a non-static member, i.e. it may not have a this
pointer<
It's true regarding stucts used as values too, and not just classes...
It would be nice if the compiler could say so: "I can't evaluate it because you are using a this pointer". With other words, but much more useful than "non-constant expression".
Aug 05 2009
parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
*On Wed, Aug 5, 2009 at 7:23 AM, Ary Borenszweig<ary esperanto.org.ar> wrot=
e:
 bearophile escribi=F3:
 Jarrett Billingsley:
 C++ has static initialization that occurs before main() too. =A0It's ju=
st..
 hidden.<
I see. I have to learn more about C++. Thank you. ------------------ Lars T. Kyllingstad:
 This is good news! The restrictions you are referring to, are they any =
of
 the ones documented here:
 http://www.digitalmars.com/d/2.0/function.html#interpretation <
That list has a point regarding what I was trying to do:
 4. the function may not be a non-static member, i.e. it may not have a
 this pointer<
It's true regarding stucts used as values too, and not just classes...
It would be nice if the compiler could say so: "I can't evaluate it becau=
se
 you are using a this pointer". With other words, but much more useful tha=
n
 "non-constant expression".
Yes, oh my God, this is the main reason I don't use CTFE: debugging them is virtually impossible, and the compiler does nothing to help there.
Aug 05 2009
parent Don <nospam nospam.com> writes:
Jarrett Billingsley wrote:
 *On Wed, Aug 5, 2009 at 7:23 AM, Ary Borenszweig<ary esperanto.org.ar> wrote:
 bearophile escribió:
 Jarrett Billingsley:
 C++ has static initialization that occurs before main() too.  It's just..
 hidden.<
I see. I have to learn more about C++. Thank you. ------------------ Lars T. Kyllingstad:
 This is good news! The restrictions you are referring to, are they any of
 the ones documented here:
 http://www.digitalmars.com/d/2.0/function.html#interpretation <
That list has a point regarding what I was trying to do:
 4. the function may not be a non-static member, i.e. it may not have a
 this pointer<
It's true regarding stucts used as values too, and not just classes...
It would be nice if the compiler could say so: "I can't evaluate it because you are using a this pointer". With other words, but much more useful than "non-constant expression".
Yes, oh my God, this is the main reason I don't use CTFE: debugging them is virtually impossible, and the compiler does nothing to help there.
Nice error messages for CTFE assignment statements are in the next release. That's probably 50% of the instances of "non-constant expression".
Aug 06 2009
prev sibling parent BCS <ao pathlink.com> writes:
Reply to bearophile,

 Jarrett Billingsley:
[...]
 ------------------
 Lars T. Kyllingstad:
Replying to two different post in the same post significantly reduces the changes that the second poster will see your reply.
Aug 05 2009
prev sibling parent reply Don <nospam nospam.com> writes:
Jarrett Billingsley wrote:
 I don't think you can call struct methods at compile-time.  Kind of
 lame, I know.  Try making norm a free function.
 
 Can the D2 compiler modified/improved to allow this?
It sure would be nice.
In fact the D1 compiler should support it too. BTW a few of the restrictions on CTFE will be removed in the next release.
Aug 05 2009
parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Don wrote:
 Jarrett Billingsley wrote:
 I don't think you can call struct methods at compile-time.  Kind of
 lame, I know.  Try making norm a free function.

 Can the D2 compiler modified/improved to allow this?
It sure would be nice.
In fact the D1 compiler should support it too. BTW a few of the restrictions on CTFE will be removed in the next release.
This is good news! The restrictions you are referring to, are they any of the ones documented here: http://www.digitalmars.com/d/2.0/function.html#interpretation or are they "undocumented" restrictions, i.e. bugs? -Lars
Aug 05 2009
parent reply Don <nospam nospam.com> writes:
Lars T. Kyllingstad wrote:
 Don wrote:
 Jarrett Billingsley wrote:
 I don't think you can call struct methods at compile-time.  Kind of
 lame, I know.  Try making norm a free function.

 Can the D2 compiler modified/improved to allow this?
It sure would be nice.
In fact the D1 compiler should support it too. BTW a few of the restrictions on CTFE will be removed in the next release.
This is good news! The restrictions you are referring to, are they any of the ones documented here: http://www.digitalmars.com/d/2.0/function.html#interpretation or are they "undocumented" restrictions, i.e. bugs? -Lars
Both. Using CTFE will be a completely different experience after the next release.
Aug 21 2009
next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Don wrote:
 Lars T. Kyllingstad wrote:
 Don wrote:
 Jarrett Billingsley wrote:
 I don't think you can call struct methods at compile-time.  Kind of
 lame, I know.  Try making norm a free function.

 Can the D2 compiler modified/improved to allow this?
It sure would be nice.
In fact the D1 compiler should support it too. BTW a few of the restrictions on CTFE will be removed in the next release.
This is good news! The restrictions you are referring to, are they any of the ones documented here: http://www.digitalmars.com/d/2.0/function.html#interpretation or are they "undocumented" restrictions, i.e. bugs? -Lars
Both. Using CTFE will be a completely different experience after the next release.
I can't wait. :) -Lars
Aug 21 2009
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Don:
Using CTFE will be a completely different experience after the next release.<
What kind of limits do you want to lift? :-) I think now LDC uses a compile-time garbage collector (beside the second one in the D runtime and the third one used by LLVM), so using CTFE&templates is better already with LDC. I like to use CTFE is to create 1D arrays at compile-time. This is a small test, it has the problem of being "fragile": if you change this code just a bit, it doesn't compile anymore. The other problem (with DMD) is that it uses a lot of RAM, even for modern standards of memory. import std.stdio: writefln; bool isPrime(int n) { if (n < 2) return false; for (int i = 2; i < n; i++) if (n % i == 0) return false; return true; } int[] genPrimes(int n) { int[] result; for (; n > 1; --n) if (isPrime(n)) result = n ~ result; return result; } static const auto primes = cast(int[900])genPrimes(7000); void main() { writefln(primes); } Currently to do such things I use templat: http://www.fantascienza.net/leonardo/so/templat.html With code like this, that's fast and uses small resources, but forces to use two languages: import std.stdio: writefln; {{ import textwrap def find_primes(n): if n < 2: return [] primes = [2] for i in xrange(2, n+1): for j in primes: if i % j == 0: break else: primes.append(i) return primes p = find_primes(7000) out = "const int primes[%d] = %s;" % (len(p), p) print "\n".join(textwrap.wrap(out, 80, subsequent_indent=" "*4)) }} void main() { writefln(primes); } Bye, bearophile
Aug 21 2009
parent Don <nospam nospam.com> writes:
bearophile wrote:
 Don:
 Using CTFE will be a completely different experience after the next release.<
What kind of limits do you want to lift? :-)
The unpredictability, mainly. Currently, it's really easy to write code that you'd expect would work in CTFE, but doesn't. Sometimes because of bugs, sometimes because of the official restrictions in the list, which are more restrictive than you'd expect. All kinds of crazy stuff is now working in my patched version of DMD. There's no improvements to the memory situation, though. That requires significant changes to several parts of the compiler. So the two most important CTFE bugs (1330 and 1382) won't be fixed in this release.
Aug 24 2009
prev sibling next sibling parent div0 <div0 users.sourceforge.net> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

bearophile wrote:

 D2 is now able to execute math functions (sin, cos, sqrt, etc) at compile time.
 
 This little C++ program compiles correctly with G++:
 
 // C++ code
 #include <math.h>
 #include <stdio.h>
 
 struct V3 {
     double x, y, z;
     V3(const double a, const double b, const double c) : x(a), y(b), z(c) {}
     V3 operator*(const double d) const { return V3(x * d, y * d, z * d); }
     V3 norm() const { return *this * (1.0 / sqrt(magsqr())); }
     double dot(const V3 &v) const { return x * v.x+y * v.y + z * v.z; }
     double magsqr() const { return dot(*this); }
 };
 
 const V3 v(V3(-0.5, -0.65, 0.9).norm());
 
 int main() {
     printf("%f %f %f\n", v.x, v.y, v.z);
     return 0;
 }
<snip>
 Do you know why?
 Can the D2 compiler modified/improved to allow this?
 
 Bye and thank you,
 bearophile
Not really relevant to the compile time issue but, your d2 code should be: import std.math; import std.stdio; struct V3 { double x, y, z; this(double _x, double _y, double _z) { x = _x; y = _y; z = _z; } V3 opMul(double d) const { return V3(x * d, y * d, z * d); } V3 norm() const { return this * (1.0 / sqrt(this.magsqr())); } double dot(ref V3 v) const { return x * v.x+y * v.y + z * v.z; } double magsqr() const { return dot(this); } } const V3 v; static this() { v = V3(1.0, 2.0, 3.0).norm(); } int main() { writefln("%f %f %f", v.x, v.y, v.z); writefln("%f", v.magsqr()); return 0; } This produces identical behavior to the c++ example. As Jarrett said, in c++ you have hidden runtime initialisation, which is made explicit in D. Having it work at compile time would be sweet. - -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iD8DBQFKed78T9LetA9XoXwRApwgAJ9Ut0GNbpDndlv5hbqFrGI0sT8PfwCgq2YQ C/C4nKF1U8ybh/nI4TBNqZk= =coIo -----END PGP SIGNATURE-----
Aug 05 2009
prev sibling parent Sergey Gromov <snake.scaly gmail.com> writes:
Tue, 04 Aug 2009 19:57:19 -0400, bearophile wrote:

 D2 is now able to execute math functions (sin, cos, sqrt, etc) at compile time.
 
 [snip]
 
 But similar D2 program produces, with DMD v.2.031:
 test.d(12): Error: non-constant expression (V3(1,2,3)).norm()
 
 // D2 code
 import std.math, std.c.stdio;
 
 struct V3 {
     double x, y, z;
     V3 opMul(double d) { return V3(x * d, y * d, z * d); }
     V3 norm() { return this * (1.0 / sqrt(this.magsqr())); }
     double dot(ref V3 v) { return x * v.x+y * v.y + z * v.z; }
     double magsqr() { return dot(this); }
 }
 
 const V3 v = V3(1.0, 2.0, 3.0).norm();
 
 int main() {
     printf("%f %f %f\n", v.x, v.y, v.z);
     return 0;
 }
You can't call methods at compile time, and you can't pass temporary by reference. This works: import std.math, std.c.stdio; struct V3 { double x, y, z; V3 opMul(double d) { return V3(x * d, y * d, z * d); } V3 norm() { return this * (1.0 / sqrt(this.magsqr())); } double dot(ref V3 v) { return x * v.x+y * v.y + z * v.z; } double magsqr() { return dot(this); } } V3 mul(ref V3 v, double d) { return V3(v.x*d, v.y*d, v.z*d); } V3 norm(V3 v) { return mul(v, 1.0 / sqrt(magsqr(v))); } double dot(ref V3 a, ref V3 b) { return a.x*b.x + a.y*b.y + a.z*b.z; } double magsqr(ref V3 v) { return dot(v, v); } const V3 v = norm(V3(1.0, 2.0, 3.0)); int main() { printf("%f %f %f\n", v.x, v.y, v.z); return 0; }
Aug 05 2009