www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - I don't get it. version(unittest) can't seem to use local variable

reply "dysmondad" <raylwhitfield gmail.com> writes:
I'm new to D. I've been using C since it was a baby and C++ back 
when it was only a pre-compiler for c. So, I may just be stuck 
thinking in C land.

The issue is I am attempting to use the version(unittest) 
feature. However the compiler pukes up the error below. I'm sure 
it's something easy enough but I've not been able to find any 
help in Google land. I don't know if I have the opOpAssign 
defined correctly or if there's something wrong with the 
constructor or both.

dysmondad Julep:~/src/D$ gdc -c velocity.d
velocity.d:110: error: no identifier for declarator v
velocity.d:110: error: semicolon expected, not '*='
velocity.d:110: error: Declaration expected, not '*='


class Velocity
{
private:

	float _Y = 0.0;
	float _X = 0.0;

public:
	this (float x, float y )
	{
		_Y = y;
		_X = x;
	}

	ref Velocity opOpAssign(string op) ( in float multiplier )
	if( op == "*" )
	{
		_Y *= multiplier;
		_X *= multiplier;
		return this;
	}
}

version(unittest)
{
	Velocity v = new Velocity( 2.0f, 5.0f );
	v *= 5.0f;  // <- line 110
	printf( "v = %s\n", to!string(v) );
}
Jul 11 2014
next sibling parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 12/07/2014 5:08 p.m., dysmondad wrote:
 I'm new to D. I've been using C since it was a baby and C++ back when it
 was only a pre-compiler for c. So, I may just be stuck thinking in C land.

 The issue is I am attempting to use the version(unittest) feature.
 However the compiler pukes up the error below. I'm sure it's something
 easy enough but I've not been able to find any help in Google land. I
 don't know if I have the opOpAssign defined correctly or if there's
 something wrong with the constructor or both.

 dysmondad Julep:~/src/D$ gdc -c velocity.d
 velocity.d:110: error: no identifier for declarator v
 velocity.d:110: error: semicolon expected, not '*='
 velocity.d:110: error: Declaration expected, not '*='


 class Velocity
 {
 private:

      float _Y = 0.0;
      float _X = 0.0;

 public:
      this (float x, float y )
      {
          _Y = y;
          _X = x;
      }

      ref Velocity opOpAssign(string op) ( in float multiplier )
      if( op == "*" )
      {
          _Y *= multiplier;
          _X *= multiplier;
          return this;
      }
 }

 version(unittest)
 {
      Velocity v = new Velocity( 2.0f, 5.0f );
      v *= 5.0f;  // <- line 110
      printf( "v = %s\n", to!string(v) );
 }
try: unittest { Velocity v = new Velocity( 2.0f, 5.0f ); v *= 5.0f; // <- line 110 printf( "v = %s\n", to!string(v) ); } instead. Basically version is like static if, it doesn't indicate its a function. Instead it changes what code gets compiled. Where as a unittest block, is essentially just a function that gets called at a special time, that is only compiled as if version(unittest) was also used.
Jul 11 2014
parent reply "dysmondad" <raylwhitfield gmail.com> writes:
.....
 try:

 unittest {
       Velocity v = new Velocity( 2.0f, 5.0f );
       v *= 5.0f;  // <- line 110
       printf( "v = %s\n", to!string(v) );
 }

 instead. Basically version is like static if, it doesn't 
 indicate its a function. Instead it changes what code gets 
 compiled.
 Where as a unittest block, is essentially just a function that 
 gets called at a special time, that is only compiled as if 
 version(unittest) was also used.
Thank you very much. That was quite helpful. So, what is the generally accepted way include unit testing? TDD is all the rage these days and I though I would try my hand at it as well as D.
Jul 12 2014
next sibling parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 13/07/2014 2:35 p.m., dysmondad wrote:
 .....
 try:

 unittest {
       Velocity v = new Velocity( 2.0f, 5.0f );
       v *= 5.0f;  // <- line 110
       printf( "v = %s\n", to!string(v) );
 }

 instead. Basically version is like static if, it doesn't indicate its
 a function. Instead it changes what code gets compiled.
 Where as a unittest block, is essentially just a function that gets
 called at a special time, that is only compiled as if
 version(unittest) was also used.
Thank you very much. That was quite helpful. So, what is the generally accepted way include unit testing? TDD is all the rage these days and I though I would try my hand at it as well as D.
Basically, have a function that does something like string manipulation or complex math? Use a unittest block for it. Which you can do before you write the function. It may not compile however. Also do note, assert's are part of the language. And will cause an exception to throw should the expression return false. assert(exp, "description"); Description is optional however. Here's an example https://github.com/rikkimax/skeleton/blob/master/source/skeleton/syntax/download_mkdir.d#L175 Of course there will be better ones, just something I was doing last night however.
Jul 12 2014
parent "dysmondad" <raylwhitfield gmail.com> writes:
...
 https://github.com/rikkimax/skeleton/blob/master/source/skeleton/syntax/download_mkdir.d#L175
 Of course there will be better ones, just something I was doing 
 last night however.
Thanks for the link and the information. That's looks like what I need so I'm going to rip off your code example. :)
Jul 12 2014
prev sibling parent "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Sun, Jul 13, 2014 at 02:35:11AM +0000, dysmondad via Digitalmars-d-learn
wrote:
[...]
 So, what is the generally accepted way include unit testing? TDD is
 all the rage these days and I though I would try my hand at it as well
 as D.
Just include unittest blocks in your program and compile with -unittest. Example: unittest { assert(myNewFunc(1,2,3) == 456); ... // whatever else to verify it } auto myNewFunc(int x, int y, int z) { ... // code here } The program will run all unittests on startup before main() executes, so you can just run it as usual. If any unittests fail it will abort with an error message. T -- What's a "hot crossed bun"? An angry rabbit.
Jul 12 2014
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 07/11/2014 10:08 PM, dysmondad wrote:

 class Velocity
 {
[...]
      ref Velocity opOpAssign(string op) ( in float multiplier )
Unrelated to your question, you want to return just Velocity there. Unlike C++, classes are reference types in D. So, Velocity itself is essentially a Velocity* in C++. Ali
Jul 11 2014
parent reply "dysmondad" <raylwhitfield gmail.com> writes:
On Saturday, 12 July 2014 at 05:23:29 UTC, Ali Çehreli wrote:
 On 07/11/2014 10:08 PM, dysmondad wrote:

 class Velocity
 {
[...]
      ref Velocity opOpAssign(string op) ( in float multiplier
) Unrelated to your question, you want to return just Velocity there. Unlike C++, classes are reference types in D. So, Velocity itself is essentially a Velocity* in C++. Ali
Right you are. I knew that but it still didn't translate into code. Thank you for pointing that out. I guess eventually I will remember that class variables are pointers. As a point of curiosity, is the ref keyword in this case simply redundant or does it actually make a difference?
Jul 12 2014
parent reply "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Sun, Jul 13, 2014 at 02:39:00AM +0000, dysmondad via Digitalmars-d-learn
wrote:
 On Saturday, 12 July 2014 at 05:23:29 UTC, Ali Çehreli wrote:
On 07/11/2014 10:08 PM, dysmondad wrote:

 class Velocity
 {
[...]
      ref Velocity opOpAssign(string op) ( in float multiplier
) Unrelated to your question, you want to return just Velocity there. Unlike C++, classes are reference types in D. So, Velocity itself is essentially a Velocity* in C++. Ali
Right you are. I knew that but it still didn't translate into code. Thank you for pointing that out. I guess eventually I will remember that class variables are pointers. As a point of curiosity, is the ref keyword in this case simply redundant or does it actually make a difference?
ref makes it possible for the caller to modify the pointer returned by the callee. For example: class D { int x; } class C { D d; this(D _d) { d = _d; } ref D getPtr() { return d; } } auto d1 = new D; auto d2 = new D; auto c = new C(d1); // c.d now points to d1 assert(c.getPtr() is d1); // getPtr returns d1 c.getPtr() = d2; // this modifies c.d assert(c.getPtr() is d2); // getPtr now returns d2 If you do not wish the caller to do this, remove the ref from the function signature. T -- Don't drink and derive. Alcohol and algebra don't mix.
Jul 12 2014
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 07/12/2014 08:37 PM, H. S. Teoh via Digitalmars-d-learn wrote:

 ref makes it possible for the caller to modify the pointer returned by
 the callee. For example:

 	class D { int x; }
 	class C {
 		D d;
 		this(D _d) { d = _d; }
 		ref D getPtr() { return d; }
 	}
 	auto d1 = new D;
 	auto d2 = new D;
 	auto c = new C(d1); // c.d now points to d1
 	assert(c.getPtr() is d1); // getPtr returns d1
 	c.getPtr() = d2; // this modifies c.d
 	assert(c.getPtr() is d2); // getPtr now returns d2

 If you do not wish the caller to do this, remove the ref from the
 function signature.
The twist here is that the OP's function returned 'this' by reference. Changing that not only not have any effect on the object, it would also be undefined behavior because 'this' is a local variable in that use. class C { ref C getPtr() { return this; } } void main() { auto c = new C(); assert(c.getPtr() is c); c.getPtr() = new C(); // modifying dead variable assert(c.getPtr() is c); // no effect } Ali
Jul 12 2014
next sibling parent "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Sat, Jul 12, 2014 at 09:20:06PM -0700, Ali Çehreli via Digitalmars-d-learn
wrote:
 On 07/12/2014 08:37 PM, H. S. Teoh via Digitalmars-d-learn wrote:
 
 ref makes it possible for the caller to modify the pointer returned by
 the callee. For example:

 	class D { int x; }
 	class C {
 		D d;
 		this(D _d) { d = _d; }
 		ref D getPtr() { return d; }
 	}
 	auto d1 = new D;
 	auto d2 = new D;
 	auto c = new C(d1); // c.d now points to d1
 	assert(c.getPtr() is d1); // getPtr returns d1
 	c.getPtr() = d2; // this modifies c.d
 	assert(c.getPtr() is d2); // getPtr now returns d2

 If you do not wish the caller to do this, remove the ref from the
 function signature.
The twist here is that the OP's function returned 'this' by reference. Changing that not only not have any effect on the object, it would also be undefined behavior because 'this' is a local variable in that use. class C { ref C getPtr() { return this; } } void main() { auto c = new C(); assert(c.getPtr() is c); c.getPtr() = new C(); // modifying dead variable assert(c.getPtr() is c); // no effect }
[...] Hmm. Shouldn't this be a compiler bug?? Returning a ref to a local variable should be illegal, even implicit ones like 'this'. T -- If you want to solve a problem, you need to address its root cause, not just its symptoms. Otherwise it's like treating cancer with Tylenol...
Jul 12 2014
prev sibling parent "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Sat, Jul 12, 2014 at 09:30:44PM -0700, H. S. Teoh via Digitalmars-d-learn
wrote:
 On Sat, Jul 12, 2014 at 09:20:06PM -0700, Ali Çehreli via Digitalmars-d-learn
wrote:
[...]
 The twist here is that the OP's function returned 'this' by
 reference.  Changing that not only not have any effect on the
 object, it would also be undefined behavior because 'this' is a
 local variable in that use.
 
 class C {
     ref C getPtr() { return this; }
 }
 
 void main()
 {
     auto c = new C();
     assert(c.getPtr() is c);
 
     c.getPtr() = new C();    // modifying dead variable
     assert(c.getPtr() is c); // no effect
 }
[...] Hmm. Shouldn't this be a compiler bug?? Returning a ref to a local variable should be illegal, even implicit ones like 'this'.
[...] Filed as bug: https://issues.dlang.org/show_bug.cgi?id=13116 It's pretty serious, since it causes memory corruption. In fact, it also breaks safe-ty (see second bug note in above link). T -- The early bird gets the worm. Moral: ewww...
Jul 12 2014