Re: unittests and templates

2010-05-11 Thread Steven Schveighoffer
On Tue, 11 May 2010 16:06:31 -0400, Steven Schveighoffer  
 wrote:




The ugly solution is to use static if like so:

static if(isIntegral!V)
{
unittest
{
}
}

But that is, well, ugly.


I found a less ugly solution -- remove the braces:

static if(isIntegral!V) unittest
{
   ...
}

This is probably fine for most purposes.

I'd still like the non-generic unit test near the function declaration.

-Steve


unittests and templates

2010-05-11 Thread Steven Schveighoffer

A cool thing I learned on the way to d2.

unittests can be templatized just like the classes/structs they reside  
in.  When enhancing dcollections with lots of detailed unit tests, I was  
doing things like this:


class ArrayList(V)
{
   V take() {...}
   unittest
   {
  auto al = new ArrayList!uint;
  al.add([0u, 1, 2, 3, 4]);
  assert(al.take() == 4);
  assert(al.length == 4);
   }
}

But I found that the unittests weren't compiling -- at all!  What I  
realized is that unittests are part of the instantiation!


At first, I was peeved, I wanted to simply test the "take" function not  
caring what type I used to instantiate the class with.  In order to do  
that, I have to move all the unit tests outside the class declaration --  
not good for maintainability.


But I came to realize -- there is great power in that feature.  For  
example, with a little change to my unit test:


unittest
{
   auto al = new ArrayList;
   al.add([cast(V)0, 1, 2, 3, 4]);
   assert(al.take() == 4);
   assert(al.length == 4);
}

I can create a global unit test that looks like this:

unittest
{
  ArrayList!uint al1;
  ArrayList!int al2;
  ArrayList!ulong al3;
  ArrayList!long al4;
}

and now my unit tests cover 4 instantiations.  With a single line, I can  
extend my unittest coverage to another type!


Of course, the issue is, how do I write a truly generic unit test?  For  
example, that 'take' unit test fails for ArrayList!string.  If I wanted to  
compile a project that happened to include the string instantiation with  
unit tests turned on, it fails to compile.


The ugly solution is to use static if like so:

static if(isIntegral!V)
{
   unittest
   {
   }
}

But that is, well, ugly.  I thought of proposing something like:

unittest if(isIntegral!V)
{
}

which looks better, but still is a bit verbose.  This might be the  
cleanest solution.  Any suggestions?


I still would like a way to do a unittest inside a template that is  
technically not part of the instantiation.  This allows you to unit test a  
function with a specific instantiation when it's not easy to build a  
generic unit test *and* you want the unit test close to the function  
declaration.  Although it's bloaty, you could just write your unittests  
like I did originally, specifying the full type in the unit test, but you  
then have to remember to create an external unit test to do the  
instantiation.


I hate to suggest static unittest :P  Any other ideas?

-Steve


Re: std.complex

2010-05-11 Thread eles
== Quote from Lars T. Kyllingstad (pub...@kyllingen.nospamnet)'s
article
> On Tue, 11 May 2010 15:08:07 +, eles wrote:
> > Maybe I am wrong, but my feeling is that if the complex numbers
were a
> > native type (like creal&co. are now), then it would have been
possible
> > to have a dedicated formatting (just like %f, %d and %s are) for
> > writefln.
> >
> > Putting the type into the library seems to forbid some very nice
things:
> >
> >  - initializing with "Complex!double z=1+2i" or "Complex!double
z=1+2*i"
> I don't think there will still be a special syntax for complex
literals
> when the built-in types are deprecated.  I'd guess not.  It is,
however,
> likely that creal etc. will be aliases for Complex!real etc.  And
this
> doesn't look that bad:
>   auto z = cdouble(1,2);

My opinion is that it does. Image writing y=(3+2i)^2+z^2*i.

OTOH, the suggestion you made below (see below)...

> >  or or
> > "Complex!double z=2.23*exp(1.107*i)" syntax (which is very
practical) -
> The following does just that, and IMO it looks a lot better:
>   auto z = fromPolar(2.23, 1.107);
> > even in C99 one could write "complex double z=1+2*I" (but "I" is a
> > defined symbol) - instead of "Complex!double(2,3)"
> If you want that, just define
>   immutable I = Complex!float(0, 1);

it is nice. However, I think it should be defined as Complex!real
(0,1);

I hope it will be automatically downsized to Complex!int if the left
value is a Complex!int and so on.

I vote for defining it in std.complex for the folowing reasons:

 - it will enforce coding discipline and standardize code among
libraries and users, the code will be consistent and copy-paste
portable.
 - it is similar to C99, already judged as acceptable for the C
community
 - if such an elementary thing is left to be defined by the
programmer, what long before not using the std.complex module at all?
I mean, as well one could re-define the whole complex library. I
think having std.complex in the standard library is primarily for
standardization and only second for its usefulness (ok, is useful
too, but I want to make a point).

 Also, I think the best is to mimick the functions in the C99
: http://www.opengroup.org/onlinepubs/009695399/basedefs/
complex.h.html

 Me, for one, I prefer writing y=z*conj(z) instead of z=z*z.conj().
OK, maybe is just personal preference.

 OTOH, I feel like maintaining x.re and x.im instead of creal(x) and
cimag(x), since the latter (as defined in C99) are only right-values.

 I have some experience with both C99 complex and with GNU Scientific
Library GSL_COMPLEX. Both have ups and downs, I still prefer to work
with C99, though.

 Also, if we are here, is any way to define ' (apostrophe) for an
(unary) operator? Having z' to mean (z conjugate) would be awesome
(y=z*z'). But maybe is just my Matlab background speaking here. Or
another character (ideas, anyone?... #z, z#, z~ or ~z etc.).

 A note of modesty: I do not try to push it harder than it is
acceptable, but since the complex numbers are just in a major
rewrite, let's try to do it in the best way. We are not constrained
by compatibility/legacy issues.

 Thanks.

 eles




Re: std.complex

2010-05-11 Thread Lars T. Kyllingstad
On Tue, 11 May 2010 15:08:07 +, eles wrote:

> Maybe I am wrong, but my feeling is that if the complex numbers were a
> native type (like creal&co. are now), then it would have been possible
> to have a dedicated formatting (just like %f, %d and %s are) for
> writefln.
> 
> Putting the type into the library seems to forbid some very nice things:
> 
>  - initializing with "Complex!double z=1+2i" or "Complex!double z=1+2*i"

I don't think there will still be a special syntax for complex literals 
when the built-in types are deprecated.  I'd guess not.  It is, however, 
likely that creal etc. will be aliases for Complex!real etc.  And this 
doesn't look that bad:

  auto z = cdouble(1,2);


>  or or
> "Complex!double z=2.23*exp(1.107*i)" syntax (which is very practical) -

The following does just that, and IMO it looks a lot better:

  auto z = fromPolar(2.23, 1.107);


> even in C99 one could write "complex double z=1+2*I" (but "I" is a
> defined symbol) - instead of "Complex!double(2,3)"

If you want that, just define

  immutable I = Complex!float(0, 1);

Perhaps it would be an idea to put that in std.complex, but I'm not 
convinced.


>  - lack of support for formatting in writef (although, that should not
>  be
> limited to native types)
>  - formatting in writef/printf is quite versatile for regular use, and
>  could be
> immediately extended to complex numbers (e.g. if one formatting is
> specified, then both real and imaginary parts would be displayed with
> that format), although 2 different complex-number formats should be
> defined: real/imaginary and amplitude/phase

This is exactly what I'm proposing.  Complex numbers don't have to be 
built-in for that.

-Lars


Re: std.complex

2010-05-11 Thread eles
Maybe I am wrong, but my feeling is that if the complex numbers were a native
type (like creal&co. are now), then it would have been possible to have a
dedicated formatting (just like %f, %d and %s are) for writefln.

Putting the type into the library seems to forbid some very nice things:

 - initializing with "Complex!double z=1+2i" or "Complex!double z=1+2*i" or or
"Complex!double z=2.23*exp(1.107*i)" syntax (which is very practical) - even in
C99 one could write "complex double z=1+2*I" (but "I" is a defined symbol) -
instead of "Complex!double(2,3)"
 - lack of support for formatting in writef (although, that should not be
limited to native types)
 - formatting in writef/printf is quite versatile for regular use, and could be
immediately extended to complex numbers (e.g. if one formatting is specified,
then both real and imaginary parts would be displayed with that format),
although 2 different complex-number formats should be defined: real/imaginary
and amplitude/phase


Re: opAddAssign still works

2010-05-11 Thread Jesse Phillips
bearophile wrote:

> Pelle:
>> Not yet, it's not. To compile something that's deprecated, you will need 
>> the -d switch.
>
> That's for user code marked with 'deprecated':
> http://www.digitalmars.com/d/2.0/attribute.html#deprecated
> I don't think it is designed to work with compiler/language features too.
>
> The D1 compiler has a switch (-v1), that's missing in D2, for deprecated 
> compiler features, maybe something similar will be put back.
>
> Bye,
> bearophile

Actually the switch has nothing to do with deprecation. Originally D2
was developed and released as the same binary as D1. If you wanted to
compile for version 1 you passed the -v1 switch, otherwise you were
compiling version 2.

Don't ask me why the switch is still there.


Re: opAddAssign still works

2010-05-11 Thread Steven Schveighoffer
On Tue, 11 May 2010 09:14:37 -0400, Simen kjaeraas  
 wrote:



Steven Schveighoffer  wrote:

But this function never gets called.  I found out recently that  
template functions are not allowed in interfaces, which makes it  
impossible to use the new operator overloads on interfaces.


The problem is however, that template functions can't be virtual, and
thus can't be stuffed into interfaces. Mayhaps however, specific
instantiations could be.

Of course, implementing some kind of dynamic vtable, that could be
updated at link-time, would make many kinds of magic possible, and
might be a solution. No idea how possible this is, though.


It is planned for interfaces to be able to contain template member  
functions, those functions would not be virtual or overridable, and would  
need to be expressed completely in terms of the interface.


They are like final interface functions.

I assumed this was already done, as it was a mitigating factor when  
fleshing out the new operator design that you could simulate previous  
behavior by creating a virtual function that then was called by your  
template operator function.


-Steve


Re: opAddAssign still works

2010-05-11 Thread Simen kjaeraas

Steven Schveighoffer  wrote:

But this function never gets called.  I found out recently that template  
functions are not allowed in interfaces, which makes it impossible to  
use the new operator overloads on interfaces.


The problem is however, that template functions can't be virtual, and
thus can't be stuffed into interfaces. Mayhaps however, specific
instantiations could be.

Of course, implementing some kind of dynamic vtable, that could be
updated at link-time, would make many kinds of magic possible, and
might be a solution. No idea how possible this is, though.

--
Simen


Re: opAddAssign still works

2010-05-11 Thread Steven Schveighoffer

On Tue, 11 May 2010 08:52:47 -0400, Trass3r  wrote:


I found out recently that template
functions are not allowed in interfaces, which makes it impossible to  
use

the new operator overloads on interfaces.


Wow that should find its way into bugzilla.


Already there :)

http://d.puremagic.com/issues/show_bug.cgi?id=4174

It was the minimal case I was working on creating where I discovered the  
old operator functions still work.


-Steve


Re: std.complex

2010-05-11 Thread Lars T. Kyllingstad
On Tue, 11 May 2010 11:51:34 +, eles wrote:

> the following test case also works:
> 
> Compiling
> 
> import std.stdio;
> import std.complex;
> 
> Complex!(double) x,y;
> 
> int main(){
>   writefln("salut!\n");
>   x.re=1;
>   x.im=1;
>   y=x.conj();
>   writefln("x=%f+%f*i\n",x.re,x.im);
>   writefln("y=%f+%f*i\n",y.re,y.im);
>   return 0;
> }
> 
> 
> results in
> 
> C:\dmd2>dmd test.d
> 
> C:\dmd2>test
> salut!
> 
> x=1.00+1.00*i
> 
> y=1.00+-1.00*i
> 
> C:\dmd2>

Cool!


> Which is OK. However, displaying complex numbers in that way is not very
> nice. Is there any dedicated formatting for that? (it would be nice to
> be able displaying a complex number in both Cartesian and Polar formats)

The problem is that there doesn't seem to be any "standard" way of 
converting stuff to strings in Phobos.

The toString() function I put into Complex is designed to write complex 
numbers to an arbitrary output range.  It may seem very verbose when all 
you want to do is to get a simple string representation, but it was meant 
as a proposal for exactly such a standard.

Another possibility was proposed by Don, as demonstrated in 
std.bigint.BigInt.toString():

http://www.digitalmars.com/d/2.0/phobos/std_bigint.html#toString

The idea is that if a type defines such a toString(), it should -- in the 
future, that is -- work automatically with std.conv.to(), 
std.stdio.writef*() etc.  Then you'd be able to do things like

auto z = Complex!real(1, -2);

auto str1 = to!string(z);
assert (str1 == "1-2i");

writefln("%.2g", z); // Prints "1.00-2.00i"

Right now, you are kind of stuck with the way you demonstrated, or you 
can have Complex.toString() write to an std.array.Appender!string range.

-Lars


Re: opAddAssign still works

2010-05-11 Thread Trass3r
> I found out recently that template
> functions are not allowed in interfaces, which makes it impossible to use
> the new operator overloads on interfaces.

Wow that should find its way into bugzilla.


Re: std.complex

2010-05-11 Thread eles
the following test case also works:

Compiling

import std.stdio;
import std.complex;

Complex!(double) x,y;

int main(){
writefln("salut!\n");
x.re=1;
x.im=1;
y=x.conj();
writefln("x=%f+%f*i\n",x.re,x.im);
writefln("y=%f+%f*i\n",y.re,y.im);
return 0;
}


results in

C:\dmd2>dmd test.d

C:\dmd2>test
salut!

x=1.00+1.00*i

y=1.00+-1.00*i

C:\dmd2>

Which is OK. However, displaying complex numbers in that way is not
very nice. Is there any dedicated formatting for that? (it would be
nice to be able displaying a complex number in both Cartesian and
Polar formats)

eles





Re: std.complex

2010-05-11 Thread eles
Confirmation: in the new beta, the test case for the std.complex
compiles on windows xp with dmd 2.046beta. I cannot post on the
D.phobos newsgroup, but I post the confirmation here.

I did not test it further.

Compiling

import std.complex;

int main(){
return 0;
}


results in:

C:\dmd2>dmd test.d

C:\dmd2>test

C:\dmd2>

While we are here, can somebody look at DMD bug 2460 please?

eles


Re: opAddAssign still works

2010-05-11 Thread Steven Schveighoffer

On Mon, 10 May 2010 19:38:53 -0400, Trass3r  wrote:


Yeah it still works for compatibility reasons but is deprecated.


Yeah, but should the old method override the new one?

I assumed one nice thing about "backwards compatibility" is you could do  
something like this:


T opOpAssign(string op)(T other) if (op == "+=")
{
   return opAddAssign(other);
}

But this function never gets called.  I found out recently that template  
functions are not allowed in interfaces, which makes it impossible to use  
the new operator overloads on interfaces.


-Steve


Re: opAddAssign still works

2010-05-11 Thread bearophile
Pelle:
> Not yet, it's not. To compile something that's deprecated, you will need 
> the -d switch.

That's for user code marked with 'deprecated':
http://www.digitalmars.com/d/2.0/attribute.html#deprecated
I don't think it is designed to work with compiler/language features too.

The D1 compiler has a switch (-v1), that's missing in D2, for deprecated 
compiler features, maybe something similar will be put back.

Bye,
bearophile


Re: opAddAssign still works

2010-05-11 Thread Pelle

On 05/11/2010 01:38 AM, Trass3r wrote:

Yeah it still works for compatibility reasons but is deprecated.


Not yet, it's not. To compile something that's deprecated, you will need 
the -d switch.


Right now, both are allowed, but the old one is scheduled for 
deprecation and presumably later removal. :)