www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Facing problems with Class Properties

reply d coder <dlang.coder gmail.com> writes:
Greetings All

I am trying to compile the following D2 code. The code giving compilation
issues is the "this()" function of the class Foo. The constructor basically
tries to initialize all the data members of the class, of type BaseClass and
of type BaseClass array.

I am using class property tupleof to iterate over members of the class. Then
I check the type of each member and if the member is a BaseClass array, I
new all the elements of the array. Otherwise if the member is of the type
BaseClass, I new it as it is.

The issue is that when I try to compile the program, I get the error
bug.d(10): Error: no property 'length' for type 'test.Bar'

I am explicitly checking the field type, and I am making sure that the field
is an array type, before looking for its length. So I am not sure why this
error appears. Please guide me.

Regards
Cherry

import std.stdio;
class BaseClass { }

class Bar: BaseClass { }

class Foo: BaseClass {
  this() {
    foreach(i, f; this.tupleof) {
      if (is (typeof(f) : BaseClass[])) {
for (size_t j = 0; j < f.length; ++j) {
  f[j] = new typeof(f[j]) ();
}
      }
      if (is(typeof(f) : BaseClass)) {
f = new typeof(f) ();
      }
    }
  }
  Bar instance1;
  Bar instance2;
  Bar [10] instances;
}

unittest {
  Foo foo;
  foo = new Foo;
}
Dec 10 2010
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 10 Dec 2010 11:35:50 -0500, d coder <dlang.coder gmail.com> wrote:

 Greetings All

 I am trying to compile the following D2 code. The code giving compilation
 issues is the "this()" function of the class Foo. The constructor  
 basically
 tries to initialize all the data members of the class, of type BaseClass  
 and
 of type BaseClass array.

 I am using class property tupleof to iterate over members of the class.  
 Then
 I check the type of each member and if the member is a BaseClass array, I
 new all the elements of the array. Otherwise if the member is of the type
 BaseClass, I new it as it is.

 The issue is that when I try to compile the program, I get the error
 bug.d(10): Error: no property 'length' for type 'test.Bar'

 I am explicitly checking the field type, and I am making sure that the  
 field
 is an array type, before looking for its length. So I am not sure why  
 this
 error appears. Please guide me.

 Regards
 Cherry

 import std.stdio;
 class BaseClass { }

 class Bar: BaseClass { }

 class Foo: BaseClass {
   this() {
     foreach(i, f; this.tupleof) {
       if (is (typeof(f) : BaseClass[])) {
 for (size_t j = 0; j < f.length; ++j) {
   f[j] = new typeof(f[j]) ();
 }
       }
       if (is(typeof(f) : BaseClass)) {
 f = new typeof(f) ();
       }
     }
   }
   Bar instance1;
   Bar instance2;
   Bar [10] instances;
 }

 unittest {
   Foo foo;
   foo = new Foo;
 }
is(typeof(f) : BaseClass[]) is a compile-time construct, yet you are trying to use it at runtime. I'm not even sure how this could compile. I imagine that you could use a recursive template to deal with the tuple, but I didn't think you could use a foreach loop. Is there a reason you can't directly reference the members? After all, you are writing the class. Another thing, is(T : U) simply means T is implicitly castable to U. Due to a compiler bug, Bar[] is implicitly castable to BaseClass[]. is(T == U) ensures that the type is exact. -Steve
Dec 10 2010
next sibling parent d coder <dlang.coder gmail.com> writes:
 Is there a reason you can't directly reference the members? =A0After all,=
you
 are writing the class.
Thanks Steve for your inputs. Actually this is part of a bigger code that I am trying to create. Though I am pretty new to D. What I have posted is a reduced code that illustrated the issue I am facing. In the actual code, I am using string mixins and there are too many classes (all derived from BaseClass) and too many class instances, and the constructor call for Bar (and other classes) is a bit more involved. There is a need to make sure that all the constructors are called in a seamless fashion. In fact, I will not be the end-user. I would just be coding the BaseClass and the mixin. The actual end-users are not supposed to be quite D-literate and I would be asking them to code something to the effect: class Foo: BaseClass { mixin(CreateInstances()); // Define your Bar and other sub-class instances here //... // More code here } Any ideas? Regards - Cherry
Dec 10 2010
prev sibling parent reply d coder <dlang.coder gmail.com> writes:
 Another thing, is(T : U) simply means T is implicitly castable to U. =A0D=
ue to
 a compiler bug, Bar[] is implicitly castable to BaseClass[].
Steve I realize that I am using this compiler bug as a feature. It would be kind of you to suggest me a code that would not exploit this bug. I was thinking of using something to the effect: if (__traits(isStaticArray, this.tupleof[i]) { if (is (typeof(this.tupleof[i][0]) : BaseModule)) { Regards - Cherry
Dec 10 2010
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 10 Dec 2010 20:22:52 -0500, d coder <dlang.coder gmail.com> wrote:

 Another thing, is(T : U) simply means T is implicitly castable to U.  
  Due to
 a compiler bug, Bar[] is implicitly castable to BaseClass[].
Steve I realize that I am using this compiler bug as a feature. It would be kind of you to suggest me a code that would not exploit this bug. I was thinking of using something to the effect: if (__traits(isStaticArray, this.tupleof[i]) { if (is (typeof(this.tupleof[i][0]) : BaseModule)) {
Just use is(T == U) instead of is(T : U) -Steve
Dec 13 2010
prev sibling next sibling parent Jesse Phillips <jessekphillips+D gmail.com> writes:
d coder Wrote:

 The issue is that when I try to compile the program, I get the error
 bug.d(10): Error: no property 'length' for type 'test.Bar'
 
 I am explicitly checking the field type, and I am making sure that the field
 is an array type, before looking for its length. So I am not sure why this
 error appears. Please guide me.
 
 Regards
 Cherry
 
 import std.stdio;
 class BaseClass { }
 
 class Bar: BaseClass { }
 
 class Foo: BaseClass {
   this() {
     foreach(i, f; this.tupleof) {
       if (is (typeof(f) : BaseClass[])) {
 for (size_t j = 0; j < f.length; ++j) {
   f[j] = new typeof(f[j]) ();
 }
       }
       if (is(typeof(f) : BaseClass)) {
 f = new typeof(f) ();
       }
     }
   }
   Bar instance1;
   Bar instance2;
   Bar [10] instances;
 }
 
 unittest {
   Foo foo;
   foo = new Foo;
 }
typeof() and is() are compile time constructs. Change your if statements to static if.
Dec 10 2010
prev sibling parent reply Jesse Phillips <jessekphillips+D gmail.com> writes:
Jesse Phillips Wrote:

 typeof() and is() are compile time constructs. Change your if statements to
 static if.
Just realized what the issue is. You are creating code as foreach becomes a static foreach when iterating a tupleof. (Yes steven it does work) This you are building code which looks like if(false) { for (size_t j = 0; j < f.length...) ... } Semantically this code is wrong as you can't take the length of f which is class Bar. The static if forces the compiler to not generate this code as it is known to be false.
Dec 10 2010
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 10 Dec 2010 15:08:34 -0500, Jesse Phillips  
<jessekphillips+D gmail.com> wrote:

 Jesse Phillips Wrote:

 typeof() and is() are compile time constructs. Change your if  
 statements to
 static if.
Just realized what the issue is. You are creating code as foreach becomes a static foreach when iterating a tupleof. (Yes steven it does work)
Ah, good to know :) -Steve
Dec 10 2010
prev sibling next sibling parent d coder <dlang.coder gmail.com> writes:
 if(false) {
 =A0 =A0for (size_t j =3D 0; j < f.length...)
 =A0 =A0...
 }

 Semantically this code is wrong as you can't take the length of f which i=
s class Bar. The static if forces the compiler to not generate this code as= it is known to be false.

Thanks Jesse

What you are saying makes sense to me. The problem is that the
following code works perfectly. I have just commented out some part
and replaced it with some debug statements.

The output from this code makes me believe that "is" and "typeof" do
have some run-time semantics. Or is it a D2 bug. BTW I am using
Digital Mars D Compiler v2.050.

Regards
- Puneet

import std.stdio;
class BaseClass { }

class Bar: BaseClass { }

class Foo: BaseClass {
  this() {
    foreach(i, f; this.tupleof) {
      if (is (typeof(this.tupleof[i]) : BaseClass[])) {
	writeln("Creating new objects for all ARRAY types ", this.tupleof[i].strin=
gof);
	// for (size_t j =3D 0; j < this.tupleof[i].length; ++j) {
	//   this.tupleof[i][j] =3D new typeof(this.tupleof[i][j]) ();
	// }
      }
      if (is(typeof(this.tupleof[i]) : BaseClass)) {
	writeln("Creating new objects for all NON-ARRAY types ",
this.tupleof[i].stringof);
	// this.tupleof[i] =3D new typeof(this.tupleof[i]) ();
      }
    }
  }
  Bar instance1;
  Bar instance2;
  Bar [10] instances;
}

unittest {
  Foo foo;
  foo =3D new Foo;
}

// I am getting the following output
// Creating new objects for all NON-ARRAY types this.instance1
// Creating new objects for all NON-ARRAY types this.instance2
// Creating new objects for all ARRAY types this.instances
Dec 10 2010
prev sibling next sibling parent d coder <dlang.coder gmail.com> writes:
 What you are saying makes sense to me. The problem is that the
 following code works perfectly. I have just commented out some part
 and replaced it with some debug statements.
Ah.. Now I think I understand. This new code I have written will all be run at compile time. So in this case, the foreach statement inside the constructor would be reduced to a bunch of writeln statements at compile time and those writeln would be executed at the run time. This will not happen with the actual code since there are other typeof and is statements in there that can not be run at runtime. Did I get it right?
Dec 10 2010
prev sibling next sibling parent reply d coder <dlang.coder gmail.com> writes:
 Ah.. Now I think I understand.

 This new code I have written will all be run at compile time. So in
 this case, the foreach statement inside the constructor would be
 reduced to a bunch of writeln statements at compile time and those
 writeln would be executed at the run time. This will not happen with
 the actual code since there are other typeof and is statements in
 there that can not be run at runtime.

 Did I get it right?
If I got it right now, It will be possible for me to unroll the foreach loop and the if statements in a mixin and that would work well. Or may be changing the "if" statement to "static if" would do the trick. I will give it a try. Thank you Steve and tank you Jesse for showing me the light. Regards - Cherry
Dec 10 2010
parent Jesse Phillips <jessekphillips+D gmail.com> writes:
d coder Wrote:

 Ah.. Now I think I understand.

 This new code I have written will all be run at compile time. So in
 this case, the foreach statement inside the constructor would be
 reduced to a bunch of writeln statements at compile time and those
 writeln would be executed at the run time. This will not happen with
 the actual code since there are other typeof and is statements in
 there that can not be run at runtime.
Yes, but the if statement will also be there so the code would look something like: if(true) writeln(...) if(false) writeln(...) ...
 If I got it right now, It will be possible for me to unroll the
 foreach loop and the if statements in a mixin and that would work
 well.
 Or may be changing the "if" statement to "static if" would do the
 trick. I will give it a try.
Static if must be done so that invalid code is not generated. As for another part of what you want. Use std.range.ElementType so that you can get the type you wish to call new for: this.tupleof[i][j] = new ElementType!(this.tupleof[i])();
Dec 10 2010
prev sibling parent spir <denis.spir gmail.com> writes:
On Sat, 11 Dec 2010 06:11:43 +0530
d coder <dlang.coder gmail.com> wrote:

 if(false) {
 =C2=A0 =C2=A0for (size_t j =3D 0; j < f.length...)
 =C2=A0 =C2=A0...
 }

 Semantically this code is wrong as you can't take the length of f which=
is class Bar. The static if forces the compiler to not generate this code = as it is known to be false.

=20
 Thanks Jesse
=20
 What you are saying makes sense to me. The problem is that the
 following code works perfectly. I have just commented out some part
 and replaced it with some debug statements.
=20
 The output from this code makes me believe that "is" and "typeof" do
 have some run-time semantics. Or is it a D2 bug. BTW I am using
 Digital Mars D Compiler v2.050.
=20
 Regards
 - Puneet
=20
 import std.stdio;
 class BaseClass { }
=20
 class Bar: BaseClass { }
=20
 class Foo: BaseClass {
   this() {
     foreach(i, f; this.tupleof) {
       if (is (typeof(this.tupleof[i]) : BaseClass[])) {
 	writeln("Creating new objects for all ARRAY types ", this.tupleof[i].str=
ingof);
 	// for (size_t j =3D 0; j < this.tupleof[i].length; ++j) {
 	//   this.tupleof[i][j] =3D new typeof(this.tupleof[i][j]) ();
 	// }
       }
       if (is(typeof(this.tupleof[i]) : BaseClass)) {
 	writeln("Creating new objects for all NON-ARRAY types ",
 this.tupleof[i].stringof);
 	// this.tupleof[i] =3D new typeof(this.tupleof[i]) ();
       }
     }
   }
   Bar instance1;
   Bar instance2;
   Bar [10] instances;
 }
=20
 unittest {
   Foo foo;
   foo =3D new Foo;
 }
=20
 // I am getting the following output
 // Creating new objects for all NON-ARRAY types this.instance1
 // Creating new objects for all NON-ARRAY types this.instance2
 // Creating new objects for all ARRAY types this.instances
Hello "d coder", Maybe this is wrong and stupid, but I have faced several times similar case= s ; meaning cases whare I perfectly knew (and D as well should have known ;= -) that a given thing was of given type, but could not access its slots. Try and downcast 'this.tupeof[i]' to the type that has a 'length'; if I'm r= ight, you're done. (I find this wrong, buggy, & ugly, but well...) Else, so= rry for the noise. Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Dec 10 2010