www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to initialize static array member variable?

reply Sebastian Schuberth <sschuberth gmail.com> writes:
Hi,

I'm still playing around with DMD 2.049 and my Vector struct. This

struct Vector(alias N,T)
{
     static immutable Vector X=Vector(1,0,0);

     this(T[N] v ...) {
         data=v;
     }

     T data[N];
};

alias Vector!(3,float) Vec3f;

gives

Error	1	Error: Slice operation this.data[] = cast(const(float[]))v 
cannot be evaluated at compile time		main.d	6

I also tried simply

struct Vector(alias N,T)
{
     static immutable Vector X=Vector(1,0,0);

     this(T x,T y,T z) {
         data[0]=x;
         data[1]=y;
         data[2]=z;
     }

     T data[N];
};

alias Vector!(3,float) Vec3f;

but that gives

Error	1	Error: Index assignment this.data[0u] = x is not yet supported 
in CTFE		main.d	6
Error	2	Error: Index assignment this.data[1u] = y is not yet supported 
in CTFE		main.d	7
Error	3	Error: Index assignment this.data[2u] = z is not yet supported 
in CTFE		main.d	8

Any other ideas how to introduce such an "X" constant?

Thanks.

-- 
Sebastian Schuberth
Sep 30 2010
next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Thu, Sep 30, 2010 at 21:14, Sebastian Schuberth <sschuberth gmail.com> w=
rote:
 Hi,

 I'm still playing around with DMD 2.049 and my Vector struct. This

 struct Vector(alias N,T)
 {
 =C2=A0 =C2=A0static immutable Vector X=3DVector(1,0,0);

 =C2=A0 =C2=A0this(T[N] v ...) {
 =C2=A0 =C2=A0 =C2=A0 =C2=A0data=3Dv;
 =C2=A0 =C2=A0}

 =C2=A0 =C2=A0T data[N];
 };

To me, your constructor's signature is saying: "give me any number of T[N]", which I guess is not what you want. You want exactly N T's. Which gives the following constructor: this(U...)(U v) if (U.length <=3D N && is(CommonType!U : T)) { data =3D [v]; } I guess I'll have to explain this: U... is a bunch of values of any type. With the template constraint I just check that 1) there is the correct number of values (at most N) 2) they can all be changed into T's as for the =3D [v] part, it's just that throwing a tuple in an array constructor will make an array from the tuple. Btw, "alias N" is a bit dangerous: N could be any symbol. As you use it as a size, let's give it a size type: Vector(int N, T) or Vector(size_t N, T). Also, T data[N]; is using a C syntax. In D, the idiomatic syntax is T[N] da= ta; And there is no need for a semicolon at the end of a struct definition: the compiler knows it ends there. Which gives us: import std.traits: CommonType; struct Vector(size_t N,T) { this(U...)(U v) if (U.length <=3D N && is(CommonType!U =3D=3D T)) { data =3D [v]; } T[N] data; }
 Any other ideas how to introduce such an "X" constant?

It's doable, but it means modifying your struct a bit: instead of holding the values in an array, you can store them in a tuple. I'll see if anyone as another idea: I'm biased towards tuples. Philippe
Sep 30 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Philippe Sigaud:

 It's doable, but it means modifying your struct a bit: instead of
 holding the values in an array, you can store them in a tuple.
 I'll see if anyone as another idea: I'm biased towards tuples.

Please, be gentle with the D newbie, don't burn his brain :-) You can't learn a big part of D2 in one day. Bye, bearophile
Sep 30 2010
prev sibling parent reply Sebastian Schuberth <sschuberth gmail.com> writes:
On 30.09.2010 22:01, Philippe Sigaud wrote:

 To me, your constructor's signature is saying: "give me any number of
 T[N]", which I guess is not what you want. You want exactly N T's.

You're right, I want exactly N T's, but from reading the section about "Typesafe Variadic Functions" at [1], I thought I'm doing exactly that. The example "For static arrays" has a comment which says for a declaration like int sum(int[3] ar ...) this return sum(2, 3); // error, need 3 values for array would not work, so I thought "...", if following a statically sized array, is a special syntax to allow the array to be initialized from exactly N scalar values. In fact, I checked that with my code auto v=Vec3f(1,0,0); compiles, but auto v=Vec3f(1,0); auto v=Vec3f(1,0,0,0); auto v=Vec3f([1,0,0],[1,0,0]); do not compile, just as desired. So I thought I'm doing the right thing :-)
 Which gives the following constructor:

 this(U...)(U v) if (U.length<= N&&  is(CommonType!U : T))
 {
      data = [v];
 }

Well, this makes sense, thank you. I'm just wondering if my solution is any less safe?
 Btw, "alias N" is a bit dangerous: N could be any symbol. As you use
 it as a size, let's give it a size type:  Vector(int N, T) or
 Vector(size_t N, T).
 Also, T data[N]; is using a C syntax. In D, the idiomatic syntax is T[N] data;
 And there is no need for a semicolon at the end of a struct
 definition: the compiler knows it ends there.

Thanks for all the hints!
 It's doable, but it means modifying your struct a bit: instead of
 holding the values in an array, you can store them in a tuple.
 I'll see if anyone as another idea: I'm biased towards tuples.

With tuples, would it still be that sizeof(Vector)==sizeof(T)*N? [1] http://www.digitalmars.com/d/2.0/function.html -- Sebastian Schuberth
Sep 30 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Sebastian Schuberth:

 With tuples, would it still be that sizeof(Vector)==sizeof(T)*N?

Yes, I think it would (if the types of the tuple are all equal I think there is no padding), a TypeTuple doen't exist at runtime, only its parts exist. In similar situations you save time asking to the compiler. Bye, bearophile
Oct 01 2010
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday 30 September 2010 12:14:09 Sebastian Schuberth wrote:
 Hi,
 
 I'm still playing around with DMD 2.049 and my Vector struct. This
 
 struct Vector(alias N,T)
 {
      static immutable Vector X=Vector(1,0,0);
 
      this(T[N] v ...) {
          data=v;
      }
 
      T data[N];
 };
 
 alias Vector!(3,float) Vec3f;
 
 gives
 
 Error	1	Error: Slice operation this.data[] = cast(const(float[]))v
 cannot be evaluated at compile time		main.d	6
 
 I also tried simply
 
 struct Vector(alias N,T)
 {
      static immutable Vector X=Vector(1,0,0);
 
      this(T x,T y,T z) {
          data[0]=x;
          data[1]=y;
          data[2]=z;
      }
 
      T data[N];
 };
 
 alias Vector!(3,float) Vec3f;
 
 but that gives
 
 Error	1	Error: Index assignment this.data[0u] = x is not yet supported
 in CTFE		main.d	6
 Error	2	Error: Index assignment this.data[1u] = y is not yet supported
 in CTFE		main.d	7
 Error	3	Error: Index assignment this.data[2u] = z is not yet supported
 in CTFE		main.d	8
 
 Any other ideas how to introduce such an "X" constant?
 
 Thanks.

You could initialized it in a static constructor. e.g. static this() { X = Vector(1, 0, 0); } By the way, it's a bit atypical in D at this point to declare constants in all caps - primarily because you often end up with so many in your code that it can get pretty ugly to have so many variables in all caps. Also, assuming that you could initialize the variable at compile-time (which you obviously having trouble doing here), the typical way to declare such a constant is not to use static but rather enum. e.g. enum x = Vector(1, 0, 0); However, since you can't initialize this particular variable at compile-time as it stands, a static variable would be the correct way to go here. Also, if you declare a variable immutable and initialize directly (as opposed to using a destructor), you don't have to include the type (just like you don't have to include the type for enum). Of course, since you need a static constructor here, it won't work here, but I thought that I'd let you know. - Jonathan M Davis
Sep 30 2010
parent Sebastian Schuberth <sschuberth gmail.com> writes:
On 30.09.2010 22:04, Jonathan M Davis wrote:

 You could initialized it in a static constructor. e.g.

 static this()
 {
 	X = Vector(1, 0, 0);
 }

I'll use that, thanks. As a side note, I find the syntax quite unfortunate. It reads to me as if the static constructor will only be called if the default constructor is used (I know, this does not make sense as the static constructor will be called before main, and before any non-static constructor). Still, I wonder why not simply the Java syntax static { // ... } was adopted. -- Sebastian Schuberth
Oct 01 2010
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Sebastian Schuberth:

 struct Vector(alias N,T)
 {
      static immutable Vector X=Vector(1,0,0);
 
      this(T[N] v ...) {
          data=v;
      }
 
      T data[N];
 };
 
 alias Vector!(3,float) Vec3f;

This seems to work: struct Vector(int N, T) { static immutable Vector x; static this() { x = Vector(1, 0, 0); } this(T[N] v...) { data = v; } T[N] data; } alias Vector!(3,float) Vec3f; void main() { auto v = Vec3f(1,2,3); v = v.x; assert(v.data[0] == 1.0); } Your code doesn't work because type safe variadic functions can't be used at compile time yet :-) It's a limitation that I think Don will eventually remove. Bye, bearophile
Sep 30 2010
prev sibling next sibling parent reply Trass3r <un known.com> writes:
 I also tried simply

 struct Vector(alias N,T)
 {
      static immutable Vector X=Vector(1,0,0);

      this(T x,T y,T z) {
          data[0]=x;
          data[1]=y;
          data[2]=z;
      }

      T data[N];
 };

This sort of constructor shouldn't be necessary since an implicit one will be generated. You could also try "alias data this;" to make the vector usable like an array. Here's a basic D2 fixed-size vector implementation for you to study: http://sfml.svn.sourceforge.net/viewvc/sfml/branches/sfml2/DSFML/import/dsfml/system/vector.d?view=markup
Sep 30 2010
next sibling parent Trass3r <un known.com> writes:
 Will it convert N T's into a T[N]?

Ah wait, yeah, he uses an array. What I mentioned works only if you have a struct with members x, y, z, ...
Sep 30 2010
prev sibling next sibling parent Sebastian Schuberth <sschuberth gmail.com> writes:
On 30.09.2010 23:10, Trass3r wrote:

 Here's a basic D2 fixed-size vector implementation for you to study:
 http://sfml.svn.sourceforge.net/viewvc/sfml/branches/sfml2/DSFML/import/dsfml/system/vector.d?view=markup

Thanks a lot, I was already looking for an example like that! -- Sebastian Schuberth
Sep 30 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Trass3r <un known.com> wrote:

 Here's a basic D2 fixed-size vector implementation for you to study:  
 http://sfml.svn.sourceforge.net/viewvc/sfml/branches/sfml2/DSFML/import/dsfml/system/vector.d?view=markup

I can't help but wonder if those neat SSE functions are a waste. Functions that use inline assembly cannot be inlined, and thus aren't necessarily faster than using good old x87. Now, if only DMD had some intrinsics for that... -- Simen
Oct 01 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Simen kjaeraas <simen.kjaras gmail.com> wrote:

 Trass3r <un known.com> wrote:

 Here's a basic D2 fixed-size vector implementation for you to study:  
 http://sfml.svn.sourceforge.net/viewvc/sfml/branches/sfml2/DSFML/import/dsfml/system/vector.d?view=markup

I can't help but wonder if those neat SSE functions are a waste. Functions that use inline assembly cannot be inlined, and thus aren't necessarily faster than using good old x87. Now, if only DMD had some intrinsics for that...

Oh, and also (if you don't mind my nitpicking), have you profiled invSqrt compared to 1/sqrt? Last time I did, I found that invSqrt was about 50% slower than 1/sqrt. The one thing I missed when looking at the code was swizzling, so I implemented it. Feel free to include it if you want, I will demand nothing for it: property Vector!(T,n.length) opDispatch(string n)() const if (allCharsValid(n,"xyzw"[0..dim])) { static if (n.length == 2) return Vector!(T,n.length)(cell[n[0]-'x'], cell[n[1]-'x']); static if (n.length == 3) return Vector!(T,n.length)(cell[n[0]-'x'], cell[n[1]-'x'], cell[n[2]-'x']); static if (n.length == 4) return Vector!(T,n.length)(cell[n[0]-'x'], cell[n[1]-'x'], cell[n[2]-'x'], cell[n[3]-'x']); } bool allCharsValid( string s, string valid ) { foreach ( e1; s ) { bool b = false; foreach (e2; valid) b |= e1 == e2; if (!b) return false; } return true; } I also wanted to allow for swizzled setters, but apparently that's currently not possible[1]. [1]: http://d.puremagic.com/issues/show_bug.cgi?id=620 -- Simen
Oct 01 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Fri, Oct 1, 2010 at 13:47, Simen kjaeraas <simen.kjaras gmail.com> wrote:
 I also wanted to allow for swizzled setters, but apparently that's
 currently not possible

What would swizzled setters look like? vec.yx = vec.xy ? vec.xy = [1,0] ? What about vec.xxx = [0,1,2]; Would Vec.x be 2 after this? Philippe
Oct 01 2010
prev sibling next sibling parent Frank Miller <frankmiller jhmi.edu> writes:
 What would swizzled setters look like?
 
 vec.yx = vec.xy ?

Yes.
 vec.xy = [1,0] ?

Maybe. Or like vec.xy = Vector!2(1,0);
 vec.xxx = [0,1,2];

No. To be an lvalue the swizzling must not contain duplicate components. For more information see p65 in the GLSL Spec. http://www.opengl.org/registry/doc/GLSLangSpec.4.00.8.clean.pdf Frank
Oct 01 2010
prev sibling next sibling parent Trass3r <un known.com> writes:
Am 01.10.2010, 13:47 Uhr, schrieb Simen kjaeraas <simen.kjaras gmail.com>:

 Oh, and also (if you don't mind my nitpicking), have you profiled
 invSqrt compared to 1/sqrt? Last time I did, I found that invSqrt
 was about 50% slower than 1/sqrt.

Haven't profiled it yet.
 The one thing I missed when looking at the code was swizzling, so
 I implemented it. Feel free to include it if you want

Thx, I incorporated it :)
 I also wanted to allow for swizzled setters, but apparently that's
 currently not possible[1].

 [1]: http://d.puremagic.com/issues/show_bug.cgi?id=620

What a pity!
Oct 29 2010
prev sibling next sibling parent Trass3r <un known.com> writes:
 I can't help but wonder if those neat SSE functions are a waste.
 Functions that use inline assembly cannot be inlined, and thus aren't
 necessarily faster than using good old x87. Now, if only DMD had some
 intrinsics for that...

Who knows. At least it was a nice exercise in writing SSE :)
Oct 29 2010
prev sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Trass3r <un known.com> wrote:

 I also wanted to allow for swizzled setters, but apparently that's
 currently not possible[1].

 [1]: http://d.puremagic.com/issues/show_bug.cgi?id=620

What a pity!

Actually, after a bit of hacking, I have found a way: // new helper function static private bool noCharsRepeated( string s ) { foreach ( i, e1; s[0..$-1]) foreach ( e2; s[i+1..$] ) if ( e1 == e2 ) return false; return true; } /// swizzling template opDispatch( string n ) { property Vector!(T,n.length) opDispatch( U... )( U args ) if (allCharsValid(n,"xyzw"[0..dim]) && (U.length == 0 || (U.length == 1 && is(U[0] == Vector!(T,n.length)) && noCharsRepeated(n)))) { static if ( U.length == 1 ) { static if ( n.length >= 1 ) cell[n[0]-'x'] = args[0].cell[0]; static if ( n.length >= 2 ) cell[n[1]-'x'] = args[0].cell[1]; static if ( n.length >= 3 ) cell[n[2]-'x'] = args[0].cell[2]; static if ( n.length >= 4 ) cell[n[3]-'x'] = args[0].cell[3]; } static if (n.length == 2) return Vector!(T,n.length)(cell[n[0]-'x'], cell[n[1]-'x']); static if (n.length == 3) return Vector!(T,n.length)(cell[n[0]-'x'], cell[n[1]-'x'], cell[n[2]-'x']); static if (n.length == 4) return Vector!(T,n.length)(cell[n[0]-'x'], cell[n[1]-'x'], cell[n[2]-'x'], cell[n[3]-'x']); } } The signature might not exactly be clean, but it works. -- Simen
Oct 29 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Thu, Sep 30, 2010 at 23:10, Trass3r <un known.com> wrote:
 This sort of constructor shouldn't be necessary since an implicit one will
 be generated.

Will it convert N T's into a T[N]?
Sep 30 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Thu, Sep 30, 2010 at 22:32, bearophile <bearophileHUGS lycos.com> wrote:
 Philippe Sigaud:

 It's doable, but it means modifying your struct a bit: instead of
 holding the values in an array, you can store them in a tuple.
 I'll see if anyone as another idea: I'm biased towards tuples.

Please, be gentle with the D newbie, don't burn his brain :-) You can't learn a big part of D2 in one day.

Well, I did say I was biased :-) So much so, in fact, that didn't see at first he was using an array. I still wonder how the constructor works: how can T[N]v... accept 1,2,3?
Sep 30 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Sebastian Schuberth <sschuberth gmail.com> wrote:

 As a side note, I find the syntax quite unfortunate. It reads to me as  
 if the static constructor will only be called if the default constructor  
 is used (I know, this does not make sense as the static constructor will  
 be called before main, and before any non-static constructor). Still, I  
 wonder why not simply the Java syntax

 static {
      // ...
 }

 was adopted.

One reason could be that {} are used for grouping in D. e.g all methods of this struct are static: struct foo { static { void bar( ) {}; string baz( ) {return "Ouch, you poked me!";} } } -- Simen
Oct 01 2010
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Fri, Oct 1, 2010 at 08:35, Sebastian Schuberth <sschuberth gmail.com> wrote:

 You're right, I want exactly N T's, but from reading the section about
 "Typesafe Variadic Functions" at [1], I thought I'm doing exactly that. The
 example "For static arrays" has a comment which says for a declaration like

 would not work, so I thought "...", if following a statically sized array,
 is a special syntax to allow the array to be initialized from exactly N
 scalar values.

 So I thought I'm doing the right thing :-)

Wow, I keep forgetting about this syntax. Looking at it in the light of your example, it seems quite useful. Philippe
Oct 01 2010