www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Remove complex and imaginary types?

reply Walter Bright <newshound1 digitalmars.com> writes:
The issue comes up now and then about why have complex and imaginary 
types, rather than using structs? All but one of the advantages of 
having them be core types can be addressed with advancing compiler 
technology. Getting rid of them will release 6 keywords, and make the 
core language simpler. Given the increasing complexity of D, this will help.

The remaining advantage is that of imaginary literals, i.e. the i postfix:

	3 + 5i

Assuming we solve the literal problem, existing code would only need to add:

	import std.complex;

to acquire complex and imaginary types.
Jan 06 2008
next sibling parent reply Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Walter Bright wrote:
 The issue comes up now and then about why have complex and imaginary 
 types, rather than using structs? All but one of the advantages of 
 having them be core types can be addressed with advancing compiler 
 technology. Getting rid of them will release 6 keywords, and make the 
 core language simpler. Given the increasing complexity of D, this will 
 help.
 
 The remaining advantage is that of imaginary literals, i.e. the i postfix:
 
     3 + 5i
 
 Assuming we solve the literal problem, existing code would only need to 
 add:
 
     import std.complex;
 
 to acquire complex and imaginary types.

Sounds like a good idea. Complex math is probably only used in a very small subset of D code, and if most advantages of having the types built in are rendered irrelevant I see no reason not to take this opportunity to simplify the language. Regarding literals, I'd say this is would be an adequate replacement for the above expression: 3 + 5*i And last, getting rid of the creal and ireal keywords can only be a good thing. :) -- Oskar
Jan 06 2008
next sibling parent davidl <davidl 126.com> writes:
在 Mon, 07 Jan 2008 15:43:51 +0800,Oskar Linde  
<oskar.lindeREM OVEgmail.com> 写道:

 Walter Bright wrote:
 The issue comes up now and then about why have complex and imaginary  
 types, rather than using structs? All but one of the advantages of  
 having them be core types can be addressed with advancing compiler  
 technology. Getting rid of them will release 6 keywords, and make the  
 core language simpler. Given the increasing complexity of D, this will  
 help.
  The remaining advantage is that of imaginary literals, i.e. the i  
 postfix:
      3 + 5i
  Assuming we solve the literal problem, existing code would only need  
 to add:
      import std.complex;
  to acquire complex and imaginary types.

Sounds like a good idea. Complex math is probably only used in a very small subset of D code, and if most advantages of having the types built in are rendered irrelevant I see no reason not to take this opportunity to simplify the language. Regarding literals, I'd say this is would be an adequate replacement for the above expression: 3 + 5*i And last, getting rid of the creal and ireal keywords can only be a good thing. :)

Oh, I didn't think of making i a struct... This would ban the use of i as a variable name. A lot of beginning tutorials use i as a variable name :) And sometimes I use it for convenience. And that would break a lot test purpose code. -- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
Jan 07 2008
prev sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Oskar Linde wrote:
 Walter Bright wrote:
 The issue comes up now and then about why have complex and imaginary 
 types, rather than using structs? All but one of the advantages of 
 having them be core types can be addressed with advancing compiler 
 technology. Getting rid of them will release 6 keywords, and make the 
 core language simpler. Given the increasing complexity of D, this will 
 help.

 The remaining advantage is that of imaginary literals, i.e. the i 
 postfix:

     3 + 5i

 Assuming we solve the literal problem, existing code would only need 
 to add:

     import std.complex;

 to acquire complex and imaginary types.

Sounds like a good idea. Complex math is probably only used in a very small subset of D code, and if most advantages of having the types built in are rendered irrelevant I see no reason not to take this opportunity to simplify the language. Regarding literals, I'd say this is would be an adequate replacement for the above expression: 3 + 5*i And last, getting rid of the creal and ireal keywords can only be a good thing. :)

The identifier "i" is rather frequently used, so I don;t think that's a good idea. I'd prefer an opPostfix or something that allows literals with postfixes to be converted to different types. This would be especially nice for dealing with units, i.e.: writef("%s", toMiles(10km + 13ft));
Jan 07 2008
parent reply renoX <renosky free.fr> writes:
Robert Fraser Wrote:

 Oskar Linde wrote:
 Walter Bright wrote:
 The issue comes up now and then about why have complex and imaginary 
 types, rather than using structs? All but one of the advantages of 
 having them be core types can be addressed with advancing compiler 
 technology. Getting rid of them will release 6 keywords, and make the 
 core language simpler. Given the increasing complexity of D, this will 
 help.

 The remaining advantage is that of imaginary literals, i.e. the i 
 postfix:

     3 + 5i

 Assuming we solve the literal problem, existing code would only need 
 to add:

     import std.complex;

 to acquire complex and imaginary types.

Sounds like a good idea. Complex math is probably only used in a very small subset of D code, and if most advantages of having the types built in are rendered irrelevant I see no reason not to take this opportunity to simplify the language. Regarding literals, I'd say this is would be an adequate replacement for the above expression: 3 + 5*i And last, getting rid of the creal and ireal keywords can only be a good thing. :)

The identifier "i" is rather frequently used, so I don;t think that's a good idea. I'd prefer an opPostfix or something that allows literals with postfixes to be converted to different types. This would be especially nice for dealing with units, i.e.: writef("%s", toMiles(10km + 13ft));

I think that you have the right suggestion here: what's wrong about the complex is that it is a too specific mechanism, having a generic built-in postfix unit mechanism would allow complex, quaternion, unit libraries.. which is very nice. In theory there is no difference between "cast(km)10 + cast(ft)13" and "10km + 13ft" but in practice there is a big one: the second one is much more readable! Regards, renoX
Jan 07 2008
parent reply "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
On Mon, 07 Jan 2008 13:21:21 -0000, renoX <renosky free.fr> wrote:

 Robert Fraser Wrote:

 Oskar Linde wrote:
 Walter Bright wrote:
 The issue comes up now and then about why have complex and imaginary
 types, rather than using structs? All but one of the advantages of
 having them be core types can be addressed with advancing compiler
 technology. Getting rid of them will release 6 keywords, and make the
 core language simpler. Given the increasing complexity of D, this  


 help.

 The remaining advantage is that of imaginary literals, i.e. the i
 postfix:

     3 + 5i

 Assuming we solve the literal problem, existing code would only need
 to add:

     import std.complex;

 to acquire complex and imaginary types.

Sounds like a good idea. Complex math is probably only used in a very small subset of D code, and if most advantages of having the types

 in are rendered irrelevant I see no reason not to take this  

 to simplify the language.

 Regarding literals, I'd say this is would be an adequate replacement  

 the above expression:

     3 + 5*i

 And last, getting rid of the creal and ireal keywords can only be a  

 thing. :)

The identifier "i" is rather frequently used, so I don;t think that's a good idea. I'd prefer an opPostfix or something that allows literals with postfixes to be converted to different types. This would be especially nice for dealing with units, i.e.: writef("%s", toMiles(10km + 13ft));

I think that you have the right suggestion here: what's wrong about the complex is that it is a too specific mechanism, having a generic built-in postfix unit mechanism would allow complex, quaternion, unit libraries.. which is very nice. In theory there is no difference between "cast(km)10 + cast(ft)13" and "10km + 13ft" but in practice there is a big one: the second one is much more readable! Regards, renoX

another language somewhere, probably a dynamic one.
Jan 07 2008
parent renoX <renosky free.fr> writes:
Bruce Adams a crit :
 On Mon, 07 Jan 2008 13:21:21 -0000, renoX <renosky free.fr> wrote:
 
 Robert Fraser Wrote:

 Oskar Linde wrote:
 Walter Bright wrote:
 The issue comes up now and then about why have complex and imaginary
 types, rather than using structs? All but one of the advantages of
 having them be core types can be addressed with advancing compiler
 technology. Getting rid of them will release 6 keywords, and make the
 core language simpler. Given the increasing complexity of D, this 


 help.

 The remaining advantage is that of imaginary literals, i.e. the i
 postfix:

     3 + 5i

 Assuming we solve the literal problem, existing code would only need
 to add:

     import std.complex;

 to acquire complex and imaginary types.

Sounds like a good idea. Complex math is probably only used in a very small subset of D code, and if most advantages of having the types

 in are rendered irrelevant I see no reason not to take this 

 to simplify the language.

 Regarding literals, I'd say this is would be an adequate 

 the above expression:

     3 + 5*i

 And last, getting rid of the creal and ireal keywords can only be a 

 thing. :)

The identifier "i" is rather frequently used, so I don;t think that's a good idea. I'd prefer an opPostfix or something that allows literals with postfixes to be converted to different types. This would be especially nice for dealing with units, i.e.: writef("%s", toMiles(10km + 13ft));

I think that you have the right suggestion here: what's wrong about the complex is that it is a too specific mechanism, having a generic built-in postfix unit mechanism would allow complex, quaternion, unit libraries.. which is very nice. In theory there is no difference between "cast(km)10 + cast(ft)13" and "10km + 13ft" but in practice there is a big one: the second one is much more readable! Regards, renoX

another language somewhere, probably a dynamic one.

Fortress has this: http://en.wikipedia.org/wiki/Fortress_%28programming_language%29 It's a language made by Sun for HPC. Regards, renoX
Jan 08 2008
prev sibling next sibling parent davidl <davidl 126.com> writes:
在 Mon, 07 Jan 2008 14:00:38 +0800,Walter Bright  
<newshound1 digitalmars.com> 写道:

 The issue comes up now and then about why have complex and imaginary  
 types, rather than using structs? All but one of the advantages of  
 having them be core types can be addressed with advancing compiler  
 technology. Getting rid of them will release 6 keywords, and make the  
 core language simpler. Given the increasing complexity of D, this will  
 help.

 The remaining advantage is that of imaginary literals, i.e. the i  
 postfix:

 	3 + 5i

 Assuming we solve the literal problem, existing code would only need to  
 add:

 	import std.complex;

 to acquire complex and imaginary types.

So it's time for implicitCastFrom? Use of imaginary literals would be limited, I can't think of a possible solution to (1+2i)*(3+5i) without support from current mechanism. Yet, I don't think that's a big deal. I don't see any possible compiler magic can deduce 1+2i firstly implicitly cast to a struct. What about the struct not getting any opMul? How well would the error be diagnosed? And even if the compiler is able to fulfill this, that means we prevent another struct/class to have implicitCastFrom(creal a) and one of opMul/opAdd/opSub/opDiv at the same time. ireal_struct myirealnumber = 2i; would work as expected by the implicitCastFrom magic. struct ireal_struct { implicitCastFrom(creal a) // and implement cfloat?, cdouble?, for different case we get different data size. use a enum to store the number? { static if( compile_time_get_real_part_func(a) != 0 ) pragma(msg,"You can't cast a non pure imaginary number to pure imaginary number."); ... } ... } The problem is that the compiler won't be able to accurately report the line of code, and not to say which column. static assert won't give you a back trace. Also I don't know the compile_time_get_real_part_func? How to get the real part or the imaginary part of a number at compile time? seems it's not yet possible. And hopefully, DMD would get the column info in the future as DMC. How to get that column info at compile time? This would make the diagnostic system becoming complexier. But if we don't implement this in the future, we get the diagnostic system inconsistency. Just like at the moment, we get some error with line numbers, while some are not. Currently I can only see three keywords which can be eliminated (ireal,ifloat,idouble). But if we want to eliminate cfloat,cdouble,creal, we come to a problem : what's typeof(3+5i)? Regards, David -- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
Jan 06 2008
prev sibling next sibling parent reply Don Clugston <dac nospam.com.au> writes:
Walter Bright wrote:
 The issue comes up now and then about why have complex and imaginary 
 types, rather than using structs? All but one of the advantages of 
 having them be core types can be addressed with advancing compiler 
 technology. Getting rid of them will release 6 keywords, and make the 
 core language simpler. Given the increasing complexity of D, this will 
 help.
 
 The remaining advantage is that of imaginary literals, i.e. the i postfix:
 
     3 + 5i
 
 Assuming we solve the literal problem, existing code would only need to 
 add:
 
     import std.complex;
 
 to acquire complex and imaginary types.

There is also the advantage of standardisation, although I don't think it's a strong argument -- AFAIK, C++ hasn't had a problem with multiple incompatible definitions of Complex. I imagine that game programmers ask, if complex numbers are built-in, why not quaternions too? I think the argument for pure imaginary types is extremely weak. They are very annoying to work with, because they aren't closed under multiplication. This is a nasty property to have in a built-in type. Suppose you're writing a generic function product(T)(T[]) which returns T[0]*T[1]*T[2]*... What's the return type? Suppose T is idouble. Then if the number of elements in T is odd, the return type should be idouble, but if it's even, the return type should be double! You could promote it to complex with a construction like typeof(1?T*T:T), but that's inefficient, and negates most of the benefits of having a imaginary type. As far as I can tell, the imaginary types could be removed even if the literal problem was not solved (the compiler could continue to keep track of imaginary literals internally, but promote them to complex whenever a type is required). But a solution to the literal problem would be impressive.
Jan 07 2008
next sibling parent John Reimer <terminal.node gmail.com> writes:
On Mon, 07 Jan 2008 09:05:45 +0100, Don Clugston wrote:

 There is also the advantage of standardisation, although I don't think
 it's a strong argument -- AFAIK, C++ hasn't had a problem with multiple
 incompatible definitions of Complex.
 I imagine that game programmers ask, if complex numbers are built-in,
 why not quaternions too?
 
 I think the argument for pure imaginary types is extremely weak. They
 are very annoying to work with, because they aren't closed under
 multiplication. This is a nasty property to have in a built-in type.
 
 Suppose you're writing a generic function product(T)(T[]) which returns
 T[0]*T[1]*T[2]*... What's the return type? Suppose T is idouble. Then if
 the number of elements in T is odd, the return type should be idouble,
 but if it's even, the return type should be double! You could promote it
 to complex with a construction like typeof(1?T*T:T), but that's
 inefficient, and negates most of the benefits of having a imaginary
 type.
 
 As far as I can tell, the imaginary types could be removed even if the
 literal problem was not solved (the compiler could continue to keep
 track of imaginary literals internally, but promote them to complex
 whenever a type is required). But a solution to the literal problem
 would be impressive.

I agree with Don (how could I not? :D), although I really have little understanding of the technical internals. Several years ago, when I first started using D, I was working on an electronics engineering course. One of my first bug reports was on D complex arithmetic. So it may be useful in some special fields, but I really don't see how it is a critical special case in D; a suitable replacement using structs would probably be more than sufficient. Furthermore, creal and ireal came across as an oxymoron. -JJR
Jan 07 2008
prev sibling parent reply Georg Wrede <georg nospam.org> writes:
Don Clugston wrote:
 Suppose you're writing a generic function product(T)(T[]) which returns 
 T[0]*T[1]*T[2]*... What's the return type?
 Suppose T is idouble. Then if the number of elements in T is odd, the 
 return type should be idouble, but if it's even, the return type should 
 be double!

I definitely don't pretend to understand any of that, but shouldn't it all follow the pertinent trails of mathematics? As in, case one, idouble; case two, double -- and the latter should probably be an idouble where one of the parts of the result De Facto makes it double, while still technically being an idouble. Any further calculation that wants to perceive a difference, might then start with checking whether the argument is "in practice a double, or really idouble".
Jan 07 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Georg Wrede wrote:
 Don Clugston wrote:
 Suppose you're writing a generic function product(T)(T[]) which 
 returns T[0]*T[1]*T[2]*... What's the return type?
 Suppose T is idouble. Then if the number of elements in T is odd, the 
 return type should be idouble, but if it's even, the return type 
 should be double!

I definitely don't pretend to understand any of that, but shouldn't it all follow the pertinent trails of mathematics? As in, case one, idouble; case two, double -- and the latter should probably be an idouble where one of the parts of the result De Facto makes it double, while still technically being an idouble. Any further calculation that wants to perceive a difference, might then start with checking whether the argument is "in practice a double, or really idouble".

The bottom line is that there really is no useful mathematics that can be performed using only imaginary numbers. If to do anything more than add, subtract, or multiply by a (real!) scalar they become complex. If you have any imaginary numbers in a numerical code it means you're working in the complex plane. I don't think there is even a mathematical symbol reserved for the set of pure imaginary numbers. For reals there's the double-barred R, for complex numbers there's double-barred C, but there's no double barred "I" as far as I know. It just isn't useful, because, as Don says, its not closed under the common mathematical operations. --bb
Jan 07 2008
parent reply Don Clugston <dac nospam.com.au> writes:
Bill Baxter wrote:
 Georg Wrede wrote:
 Don Clugston wrote:
 Suppose you're writing a generic function product(T)(T[]) which 
 returns T[0]*T[1]*T[2]*... What's the return type?
 Suppose T is idouble. Then if the number of elements in T is odd, the 
 return type should be idouble, but if it's even, the return type 
 should be double!

I definitely don't pretend to understand any of that, but shouldn't it all follow the pertinent trails of mathematics? As in, case one, idouble; case two, double -- and the latter should probably be an idouble where one of the parts of the result De Facto makes it double, while still technically being an idouble. Any further calculation that wants to perceive a difference, might then start with checking whether the argument is "in practice a double, or really idouble".

The bottom line is that there really is no useful mathematics that can be performed using only imaginary numbers. If to do anything more than add, subtract, or multiply by a (real!) scalar they become complex. If you have any imaginary numbers in a numerical code it means you're working in the complex plane. I don't think there is even a mathematical symbol reserved for the set of pure imaginary numbers. For reals there's the double-barred R, for complex numbers there's double-barred C, but there's no double barred "I" as far as I know. It just isn't useful, because, as Don says, its not closed under the common mathematical operations.

Right. In practice, I've found that you always convert ireal to real whenever you want to do anything interesting. 100% of the benefits of ireal could be obtained by including a guaranteed optimisation that complexA * realR * complex_literalB becomes simply complex(-A.im*R*B.im, A.re*R*B.im) when the literal B has a real part of zero. (and similarly for division). Note that if the literal is 1i, then R behaves exactly as an ireal. The *only* difference is that the programmer has to remember that it's imaginary (by multiplying by 1i) instead of the compiler remembering it in the type.
Jan 08 2008
parent BCS <ao pathlink.com> writes:
Reply to Don,

 
 100% of the benefits of ireal could be obtained by including a
 guaranteed optimisation that
 
 complexA * realR * complex_literalB
 
 becomes simply complex(-A.im*R*B.im, A.re*R*B.im)
 when the literal B has a real part of zero.
 (and similarly for division).

This is starting to touch on something I have been wanting: compile time access to literals. In my backmath lib you can't use literal values: A + B = C * 3; // fails 3 is of wrong type One thing that would fix this quite well would be to allow a "constant cast" where constant is really constant. with this: Value!(v) implicitCast(real v)(){return Value!(v).init} the above processes as: A + B = C * implicitCast!(3)(); Having access to literal values at the typing stage would allow all kinds of cool stuff at compile time.
Jan 08 2008
prev sibling next sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Walter Bright wrote:
 The issue comes up now and then about why have complex and imaginary 
 types, rather than using structs? All but one of the advantages of 
 having them be core types can be addressed with advancing compiler 
 technology. Getting rid of them will release 6 keywords, and make the 
 core language simpler. Given the increasing complexity of D, this will 
 help.
 
 The remaining advantage is that of imaginary literals, i.e. the i postfix:
 
     3 + 5i
 
 Assuming we solve the literal problem, existing code would only need to 
 add:
 
     import std.complex;
 
 to acquire complex and imaginary types.

I never use them in the style of code I write, so I personally wouldn't miss them. I think for code that does need it, if (and only if) the same performance benefits can be seen in a struct, it will simplify the language enough to justify their removal.
Jan 07 2008
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 The issue comes up now and then about why have complex and imaginary 
 types, rather than using structs? All but one of the advantages of 
 having them be core types can be addressed with advancing compiler 
 technology. Getting rid of them will release 6 keywords, and make the 
 core language simpler. Given the increasing complexity of D, this will 
 help.
 
 The remaining advantage is that of imaginary literals, i.e. the i postfix:
 
     3 + 5i
 
 Assuming we solve the literal problem, existing code would only need to 
 add:
 
     import std.complex;
 
 to acquire complex and imaginary types.

I defer to Don on this one :-) But I will say I seem to have heard arguments like this pretty often: "Well complex numbers are built-in, and my <new confoobulator> will be used at least as much as complex numbers." So that seems a little telling to me. I personally haven't had much need for complex numbers, but I maintain wrappers for a number of Fortran math libraries which have APIs for cfloat and cdouble. My main fear is just that going from built-in to not means I'll need to maintain different versions of these for D1.0, D2.0, and maybe D2.0/Tango when that comes out. Right now I think they're pretty much version independent. --bb
Jan 07 2008
parent reply "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
On Mon, 07 Jan 2008 08:35:20 -0000, Bill Baxter  
<dnewsgroup billbaxter.com> wrote:

 Walter Bright wrote:
 The issue comes up now and then about why have complex and imaginary  
 types, rather than using structs? All but one of the advantages of  
 having them be core types can be addressed with advancing compiler  
 technology. Getting rid of them will release 6 keywords, and make the  
 core language simpler. Given the increasing complexity of D, this will  
 help.
  The remaining advantage is that of imaginary literals, i.e. the i  
 postfix:
      3 + 5i
  Assuming we solve the literal problem, existing code would only need  
 to add:
      import std.complex;
  to acquire complex and imaginary types.

I defer to Don on this one :-) But I will say I seem to have heard arguments like this pretty often: "Well complex numbers are built-in, and my <new confoobulator> will be used at least as much as complex numbers." So that seems a little telling to me.

excuses as justifications for their pet new syntax feature proposal. I think complex numbers like any other feature have to stand or not on their own.
 I personally haven't had much need for complex numbers, but I maintain  
 wrappers for a number of Fortran math libraries which have APIs for  
 cfloat and cdouble.  My main fear is just that going from built-in to  
 not means I'll need to maintain different versions of these for D1.0,  
 D2.0, and maybe D2.0/Tango when that comes out.  Right now I think  
 they're pretty much version independent.

 --bb

My own feeling is if it ain't broke don't fix it. Walter must have something up his sleeve if he's thinking of changing it. It could just be cosmetic. Its common in a new language for features to be hard coded and gradually replaced with libraries as the language becomes strong enough to support better modularity. I can't think of any other language where complex numbers are built in rather than a library (only because I've never looked mind). However, I can't think of any language that has a rich enough syntax to let you write 3+5i like that. Though I can see it happening in a duck typed language. Bruce.
Jan 07 2008
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Bruce Adams wrote:
 On Mon, 07 Jan 2008 08:35:20 -0000, Bill Baxter 
 <dnewsgroup billbaxter.com> wrote:
 
 Walter Bright wrote:
 The issue comes up now and then about why have complex and imaginary 
 types, rather than using structs? All but one of the advantages of 
 having them be core types can be addressed with advancing compiler 
 technology. Getting rid of them will release 6 keywords, and make the 
 core language simpler. Given the increasing complexity of D, this 
 will help.
  The remaining advantage is that of imaginary literals, i.e. the i 
 postfix:
      3 + 5i
  Assuming we solve the literal problem, existing code would only need 
 to add:
      import std.complex;
  to acquire complex and imaginary types.

I defer to Don on this one :-) But I will say I seem to have heard arguments like this pretty often: "Well complex numbers are built-in, and my <new confoobulator> will be used at least as much as complex numbers." So that seems a little telling to me.

wonderful excuses as justifications for their pet new syntax feature proposal. I think complex numbers like any other feature have to stand or not on their own.
 I personally haven't had much need for complex numbers, but I maintain 
 wrappers for a number of Fortran math libraries which have APIs for 
 cfloat and cdouble.  My main fear is just that going from built-in to 
 not means I'll need to maintain different versions of these for D1.0, 
 D2.0, and maybe D2.0/Tango when that comes out.  Right now I think 
 they're pretty much version independent.

 --bb

My own feeling is if it ain't broke don't fix it. Walter must have something up his sleeve if he's thinking of changing it. It could just be cosmetic.

I think he's sensitive about the number-of-keywords argument people sometimes bring up against D. The count for D could drop by 6 by making complex numbers a library. Anyway, as Don so eloquently pointed out, pure imaginary types of any form don't make much sense in a programming language.
 Its common in a new
 language for features to be hard coded and gradually replaced with 
 libraries as the
 language becomes strong enough to support better modularity. I can't 
 think of any other
 language where complex numbers are built in rather than a library (only 
 because I've
 never looked mind). However, I can't think of any language that has a 
 rich enough syntax
 to let you write 3+5i like that. Though I can see it happening in a duck 
 typed language.

I know of two: Fortran and python both have complex numbers built in (but neither has a built-in pure imaginary type). Fortran has em because the language was designed mainly for engineering work, and engineers can't live without complex numbers. At least back in 1977 Fortran had no way to define user types, so built-in was the obvious choice. I'm not sure why Python has them built-in. It doesn't really seem necessary. Maybe Guido just wanted to draw in the engineers. It even uses the engineering convention of j for sqrt(-1). 1+1j rather than 1+1i. --bb
Jan 07 2008
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Bruce Adams wrote:
 I can't think of any other
 language where complex numbers are built in rather than a library (only 
 because I've never looked mind).

Python, C and Fortran.
Jan 07 2008
prev sibling next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 The issue comes up now and then about why have complex and imaginary 
 types, rather than using structs? All but one of the advantages of 
 having them be core types can be addressed with advancing compiler 
 technology. Getting rid of them will release 6 keywords, and make the 
 core language simpler. Given the increasing complexity of D, this will 
 help.
 
 The remaining advantage is that of imaginary literals, i.e. the i postfix:
 
     3 + 5i
 
 Assuming we solve the literal problem, existing code would only need to 
 add:
 
     import std.complex;
 
 to acquire complex and imaginary types.

While some way to write complex literals would be neat (because presumably it would open the door to being able to make literal syntaxes for all user types) I don't think it's really a killer. It's not very common to use lots of literals. For a command-line tool not having a literal syntax can be a bummer, but for a programming language it's bad practice to have a lot of magic literals in your code anyway. I.e. creal rot45 = creal(.707, 707); creal xr = rot45 * x; is better than creal xr = (.707 + 0.707i) * x; in my opinion. As long as complex constants can still be put in static arrays, it should be ok. --bb
Jan 07 2008
prev sibling next sibling parent reply Georg Wrede <georg nospam.org> writes:
Walter Bright wrote:
 The issue comes up now and then about why have complex and imaginary 
 types, rather than using structs?  

Assuming the opponents of the D programming language are not reading this, I'd like to remind you of the upsides. A language that is C(++) like, and that endorses Complex and Imaginary types right in the language itself, gains a few points in any "cross-the-tees" language comparison. Additionally, while any "self-respecting professional" doesn't let his reputation degrade into falling for such "mundaneties", some of the critics (especially those who actually are capable of creating their own opinion based on their experience and intellect, as opposed to the average opinion at the golf club), surely would welcome the notion of having these data types chiseled right into the language -- irrespectively of whether there is a Canonical library implementation or not.
 All but one of the advantages of having them be core types can be
 addressed with advancing compiler technology.

No argument there. But then, what is the whole point of the issue? IMHO, the notion of having them as Fundamental, or Canonical Types in the language, is totally decoupled from the fact that they are or not are handled in some "bundled library". The fact that they are recognised in the language itself, is far more valuable than whether they are at all (or Perfectly) addressed in some library (included or not, or even that you have to buy at (possibly outrageous) cost).
 Getting rid of them will release 6 keywords, and make the 
 core language simpler.

Now, this is the one subject that gets me downright ballistic. During the (some six) years I've been a part of D, I have constantly had a problem with this keyword number issue. I've studied languages, I've taught Computer Programming for years at University Level, and, to this day, I haven't got a compelling answer to "why less keywords is Better, "Even at the cost of confusing any or all of the students of a particular language"". I've also studied Natural Languages (as in Finnish, Swedish, English, German, Spanish, Russian, French), and during those years, I've gotten a fair idea of the relation of the number of words versus the number of concepts, and how these relate to the understandability and learning speed of them. As a result of this all, I'm definitely of the opinion that "one concept warrants one word", and that "the same word for different purposes is poison", and that "the same concept with different words is poison". (Do I have to say "const", anybody???")
 The remaining advantage is that of imaginary literals, i.e. the i postfix:
 
     3 + 5i

I'd really like to reserve the above phrase to be reserved to mean an imaginary number. If one has the library delivered right with the standard compiler or if one has to walk around the Globe in search of the One library that actually implements it, I'd still want to have this particular notation reserved (in the Language Grammar itself) for this particular purpose.
 Assuming we solve the literal problem, existing code would only need to 
 add:
 
     import std.complex;
 
 to acquire complex and imaginary types.

Yes, of course. If the standard library doesn't implement imaginary, then the most rational thing to do would be to write "import whatever.complex". In any case, the notation "3 + 5i" should be reserved for imaginary numbers, period. Whether the original compiler writer bothers to deliver the relevant library implementation or not, is besides the issue. A Serious Language ought to have this notation chiseled down. ========================================= Now, having said all that, if it turns out that Walter's ONLY suggestion here was that instead of simply using "3 + 5i" instead of preceding it with "import std.complex" -- please, then, disreagard this entire post. Still, some of my points may be valid even so. :-)
Jan 07 2008
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Georg Wrede wrote:
 Walter Bright wrote:
 The issue comes up now and then about why have complex and imaginary 
 types, rather than using structs?  

the notion of having them as Fundamental, or Canonical Types in the language, is totally decoupled from the fact that they are or not are handled in some "bundled library". The fact that they are recognised in the language itself, is far more valuable than whether they are at all (or Perfectly) addressed in some library (included or not, or even that you have to buy at (possibly outrageous) cost).

There is one thing we'd lose that hasn't been mentioned. We'd lose the ability to have complex template parameters. But maybe it's time to extend that capability to all value types, anyway.
 The remaining advantage is that of imaginary literals, i.e. the i 
 postfix:

     3 + 5i

I'd really like to reserve the above phrase to be reserved to mean an imaginary number.

You seem to be mixing up imaginary and complex. But anyway, as per Don's comment, regardless of what else happens it's probably a good idea to make 5i be a complex number with zero real part, rather than a pure imaginary number. And do away with the pure-imaginary types.
 If one has the library delivered right with the 
 standard compiler or if one has to walk around the Globe in search of 
 the One library that actually implements it, I'd still want to have this 
 particular notation reserved (in the Language Grammar itself) for this 
 particular purpose.
 
 Assuming we solve the literal problem, existing code would only need 
 to add:

     import std.complex;

 to acquire complex and imaginary types.

Yes, of course. If the standard library doesn't implement imaginary, then the most rational thing to do would be to write "import whatever.complex". In any case, the notation "3 + 5i" should be reserved for imaginary numbers, period.

I don't think it could really work that way. Upon encountering the text 3+5i the compiler has to know what sort of value to create. If it has to import a module to know what type that is then that module is going to have to be somehow hard-coded. The result is basically that it has to be a built-in type. Unless of course Walter invents a general way to associate literal suffixes with user types. --bb
Jan 07 2008
prev sibling next sibling parent reply John Reimer <terminal.node gmail.com> writes:
On Tue, 08 Jan 2008 04:38:44 +0200, Georg Wrede wrote:
 Getting rid of them will release 6 keywords, and make the core language
 simpler.

Now, this is the one subject that gets me downright ballistic. During the (some six) years I've been a part of D, I have constantly had a problem with this keyword number issue. I've studied languages, I've taught Computer Programming for years at University Level, and, to this day, I haven't got a compelling answer to "why less keywords is Better, "Even at the cost of confusing any or all of the students of a particular language"". I've also studied Natural Languages (as in Finnish, Swedish, English, German, Spanish, Russian, French), and during those years, I've gotten a fair idea of the relation of the number of words versus the number of concepts, and how these relate to the understandability and learning speed of them. As a result of this all, I'm definitely of the opinion that "one concept warrants one word", and that "the same word for different purposes is poison", and that "the same concept with different words is poison". (Do I have to say "const", anybody???")

Wow... I've had the same feelings (without the experiences, however), but you elucidated a thought I've had in my mind for awhile about the "too many keywords" problem. I wasn't sure how to express it, nor do I really have the language background to make the argument stronger. It seems to me that the languages (computer or natural) with more vocabulary are more expressive in describing an exact thought. Whereas simpler languages seem prone to use many context sensitive words that could only express complete thoughts with laborious diatribe (such is the result of limited vocabulary, I suppose, in any language). The advantage of reduced vocabulary is lost when simplicity of vocabulary causes a complexity of volume (and possibly ambiguity). There is a risk, therefore, of communication being lost. Whereas, increased vocabulary seems to simplify the sentence at the expense of comprehension (the issuer and receiver must memorize more words and understand more meanings). Once again, there's a another risk of the communication being lost. So, which is the worse evil? When it comes to natural languages, there are thousands of words to memorize, and developing a vocabulary is a constant challenge for language learners. In the case of computer languages, the keyword vocabulary is a minuscule fraction of the natural language, so it would seem unreasonable for us to worry about such additions, especially if they improve the languages ability to express exact meaning. But this is hardly original thought when it comes to language design, I'm sure. For those that have studied language design, I imagine this is probably one of the first things discussed. I'm not sure if I'm babbling on with this, but I just wanted to voice some sort of agreement with Georg's take on this. -JJR
Jan 07 2008
parent Sean Kelly <sean f4.ca> writes:
John Reimer wrote:
 
 I'm not sure if I'm babbling on with this, but I just wanted to voice 
 some sort of agreement with Georg's take on this.  

Yes, it was well expressed and I feel much the same. Sean
Jan 08 2008
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Georg Wrede wrote:
 Assuming the opponents of the D programming language are not reading 
 this, I'd like to remind you of the upsides.

Sure. Hearing both sides is why I posted the query.
 A language that is C(++) like, and that endorses Complex and Imaginary 
 types right in the language itself, gains a few points in any 
 "cross-the-tees" language comparison. Additionally, while any 
 "self-respecting professional" doesn't let his reputation degrade into 
 falling for such "mundaneties", some of the critics (especially those 
 who actually are capable of creating their own opinion based on their 
 experience and intellect, as opposed to the average opinion at the golf 
 club), surely would welcome the notion of having these data types 
 chiseled right into the language -- irrespectively of whether there is a 
 Canonical library implementation or not.

I wouldn't remove it from the core language without having a complete standard library implementation ready to go.
 IMHO, 
 the notion of having them as Fundamental, or Canonical Types in the 
 language, is totally decoupled from the fact that they are or not are 
 handled in some "bundled library".

I don't agree. Things that should go into the core language are things that don't work very well as libraries. If they do work well as libraries, then it's hard to see the value of putting them in the core.
 The fact that they are recognised in the language itself, is far more 
 valuable than whether they are at all (or Perfectly) addressed in some 
 library (included or not, or even that you have to buy at (possibly 
 outrageous) cost).

They'd be standardized and included with any standard conforming D implementation.
 Getting rid of them will release 6 keywords, and make the core 
 language simpler.

Now, this is the one subject that gets me downright ballistic. During the (some six) years I've been a part of D, I have constantly had a problem with this keyword number issue. I've studied languages, I've taught Computer Programming for years at University Level, and, to this day, I haven't got a compelling answer to "why less keywords is Better, "Even at the cost of confusing any or all of the students of a particular language"". I've also studied Natural Languages (as in Finnish, Swedish, English, German, Spanish, Russian, French), and during those years, I've gotten a fair idea of the relation of the number of words versus the number of concepts, and how these relate to the understandability and learning speed of them. As a result of this all, I'm definitely of the opinion that "one concept warrants one word", and that "the same word for different purposes is poison", and that "the same concept with different words is poison".

While I agree that lots-o-keywords is not necessarily a bad thing, it is an indication that all might not be well with the language design. A perfect language would have a very small number of orthogonal concepts, from which elegant constructs can be built. For example, closures are a simple concept, which obsoletes the more complex feature functors.
 (Do I have to say "const", anybody???")

Oddly enough, the current const regime is the simplest of all the proposals.
 The remaining advantage is that of imaginary literals, i.e. the i 
 postfix:

     3 + 5i

I'd really like to reserve the above phrase to be reserved to mean an imaginary number. If one has the library delivered right with the standard compiler or if one has to walk around the Globe in search of the One library that actually implements it, I'd still want to have this particular notation reserved (in the Language Grammar itself) for this particular purpose.

I do too. And been thinking along the lines of simply putting a hack in that the postfix 'i' means that it's a literal of type 'imaginary', and the compiler looks to see if "std.complex" was imported. This isn't as outlandish as it sounds, as there's precedent for it both in C++ <typeinfo> and java.lang.String, as well as D's Object.
Jan 07 2008
next sibling parent reply Daniel919 <Daniel919 web.de> writes:
 The remaining advantage is that of imaginary literals, i.e. the i 
 postfix:

     3 + 5i

I'd really like to reserve the above phrase to be reserved to mean an imaginary number. If one has the library delivered right with the standard compiler or if one has to walk around the Globe in search of the One library that actually implements it, I'd still want to have this particular notation reserved (in the Language Grammar itself) for this particular purpose.

I do too. And been thinking along the lines of simply putting a hack in that the postfix 'i' means that it's a literal of type 'imaginary', and the compiler looks to see if "std.complex" was imported. This isn't as outlandish as it sounds, as there's precedent for it both in C++ <typeinfo> and java.lang.String, as well as D's Object.

What about a more general solution like ----------------------------- import std.stdio, std.conv; struct complex { real re; real im; complex opAdd(real r) { return complex(re+r, im); } complex opAdd_r(real r) { return complex(re+r, im); } complex opAdd(complex c) { return complex(re+c.re, im+c.im); } string toString() { return std.conv.toString(re) ~ "+" ~ std.conv.toString(im) ~ "i"; } } //complex opPostfix("i")(T)(T im) { return complex(0,im); } void main() { // complex c = 1+5i + 2+3i + 6i; complex c = 1+complex(0,5) + 2+complex(0,3) + complex(0,6); writefln( c ); } ----------------------------- This would also allow real opPostfix("L")(T)(T x) { return x; } T opPostfix("k")(T)(T x) { return x * 1000; } meter opPostfix("m")(T)(T x) { return meter(x); }
Jan 08 2008
parent Leandro Lucarella <llucax gmail.com> writes:
Daniel919, el  8 de enero a las 12:22 me escribiste:
 What about a more general solution like
 -----------------------------
 import std.stdio, std.conv;
 
 struct complex {
     real re;
     real im;
     complex opAdd(real r) { return complex(re+r, im); }
     complex opAdd_r(real r) { return complex(re+r, im); }
     complex opAdd(complex c) { return complex(re+c.re, im+c.im); }
     string toString() { return std.conv.toString(re) ~ "+" ~
std.conv.toString(im) ~ "i"; 
 }
 }
 
 //complex opPostfix("i")(T)(T im) { return complex(0,im); }
 
 void main() {
 //    complex c =      1+5i      +     2+3i       +     6i;
     complex c = 1+complex(0,5) + 2+complex(0,3) + complex(0,6);
     writefln( c );
 }
 -----------------------------
 
 This would also allow
 
 real opPostfix("L")(T)(T x) { return x; }
 
 T opPostfix("k")(T)(T x) { return x * 1000; }
 meter opPostfix("m")(T)(T x) { return meter(x); }

+1 -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Sus discipulos se miraron sin entended hasta que uno preguntose: Peperino, soy Daniel Q. de Olivos tengo 54 años y aún soy virgen. A lo que Peperino respondiole: Si sos ganso, ganso ser. Y lo frotó, y lo curó y lo sanó. A lo que todos dijeron: ­¡¡¡Peperino se la come, Peperino se la come!!! -- Peperino Pómoro
Jan 08 2008
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Walter Bright Wrote:
 I do too. And been thinking along the lines of simply putting a hack in 
 that the postfix 'i' means that it's a literal of type 'imaginary', and 
 the compiler looks to see if "std.complex" was imported.
 
 This isn't as outlandish as it sounds, as there's precedent for it both 
 in C++ <typeinfo> and java.lang.String, as well as D's Object.

Any time a hack is needed, it's probably not the best solution. Somewhere in this thread, people talked about a generic interface for postfix labels. Examples given were i, ft, km. I'd be really cool to see something like that make its way into the language instead of a hack.
Jan 08 2008
parent Christopher Wright <dhasenan gmail.com> writes:
Jason House wrote:
 Walter Bright Wrote:
 I do too. And been thinking along the lines of simply putting a hack in 
 that the postfix 'i' means that it's a literal of type 'imaginary', and 
 the compiler looks to see if "std.complex" was imported.

 This isn't as outlandish as it sounds, as there's precedent for it both 
 in C++ <typeinfo> and java.lang.String, as well as D's Object.

Any time a hack is needed, it's probably not the best solution. Somewhere in this thread, people talked about a generic interface for postfix labels. Examples given were i, ft, km. I'd be really cool to see something like that make its way into the language instead of a hack.

I'd rather it were not. It reduces clarity, since the postfixes will be short and there will be a lot of collisions and it won't be clear where they are defined.
Jan 08 2008
prev sibling next sibling parent Sean Kelly <sean f4.ca> writes:
Walter Bright wrote:
 Georg Wrede wrote:
 
 The remaining advantage is that of imaginary literals, i.e. the i 
 postfix:

     3 + 5i

I'd really like to reserve the above phrase to be reserved to mean an imaginary number. If one has the library delivered right with the standard compiler or if one has to walk around the Globe in search of the One library that actually implements it, I'd still want to have this particular notation reserved (in the Language Grammar itself) for this particular purpose.

I do too. And been thinking along the lines of simply putting a hack in that the postfix 'i' means that it's a literal of type 'imaginary', and the compiler looks to see if "std.complex" was imported. This isn't as outlandish as it sounds, as there's precedent for it both in C++ <typeinfo> and java.lang.String, as well as D's Object.

I thought the standard library's inclusion in the language spec was one of the things you disliked about C++. Though you're right there is effective precedent for it, with the compiler recognizing std.intrinsic and various parts of std.math as a QOI feature. However, this has proven to be quite a headache for libraries with alternate path schemes, like Tango. I'll admit to also being a bit concerned that this may produce another binding between the runtime and standard library, much like the regex features did. I'm all for retaining imaginary literals, but I hope the solution is carefully considered. Sean
Jan 08 2008
prev sibling parent Georg Wrede <georg nospam.org> writes:
Walter Bright wrote:
 Georg Wrede wrote:
 
 While I agree that lots-o-keywords is not necessarily a bad thing, it is 
 an indication that all might not be well with the language design. A 
 perfect language would have a very small number of orthogonal concepts, 
 from which elegant constructs can be built.

Lisp? :-) But seriously, I'd say that once you have a well designed language, the number of keywords automagically stays low. But any cheating (as in overloading words, for example) makes the language harder to use and/or harder to learn. Almost as bad is when one contemplates the inclusion of a new concept into the language, and in hindsight finds himself having decided according to whether the concept needs a new keyword. (Hell, I'd almost swear I've seen that happen sometime. :-) )
 (Do I have to say "const", anybody???")


(Sloppily referred to the old const...)
 Oddly enough, the current const regime is the simplest of all the 
 proposals.

No argument there!
Jan 08 2008
prev sibling parent reply Don Clugston <dac nospam.com.au> writes:
Georg Wrede wrote:
 Getting rid of them will release 6 keywords, and make the core 
 language simpler.

Now, this is the one subject that gets me downright ballistic. During the (some six) years I've been a part of D, I have constantly had a problem with this keyword number issue.

 As a result of this all, I'm definitely of the opinion that "one concept
 warrants one word", and that "the same word for different purposes is
 poison", and that "the same concept with different words is poison".

 (Do I have to say "const", anybody???")

There's a funny thing about this situation. Here's the background: * I argued (on the ng) against overloading the 'enum' keyword to mean manifest constants. * Andrei emailed me, basically saying that we need to keep the keyword count down. * I responded that if we want to get the keyword count down, an obvious way to do it would be to remove the pure imaginary types. * Andrei discussed this with Walter. Essentially, I don't think that pure imaginary types belong in the language (not even in a standard library). And getting rid of them would be great news for those who care about keyword count. The complex types are different; the _only_ reason you'd remove them is to reduce the keyword count. That's a completely different issue. -Don.
Jan 08 2008
parent reply Georg Wrede <georg nospam.org> writes:
Don Clugston wrote:
 Georg Wrede wrote:
 
 Getting rid of them will release 6 keywords, and make the core 
 language simpler.

Now, this is the one subject that gets me downright ballistic. During the (some six) years I've been a part of D, I have constantly had a problem with this keyword number issue.

 As a result of this all, I'm definitely of the opinion that "one concept
 warrants one word", and that "the same word for different purposes is
 poison", and that "the same concept with different words is poison".

 (Do I have to say "const", anybody???")

There's a funny thing about this situation. Here's the background: * I argued (on the ng) against overloading the 'enum' keyword to mean manifest constants. * Andrei emailed me, basically saying that we need to keep the keyword count down.

This should NEVER be an isolated goal. Rather, it should just be the natural result of good language design. And only that. BASIC and Brainf**k have fewer keywords than D, but I wouldn't call them better than D.
 * I responded that if we want to get the keyword count down, an obvious 
 way to do it would be to remove the pure imaginary types.
 * Andrei discussed this with Walter.
 
 Essentially, I don't think that pure imaginary types belong in the 
 language (not even in a standard library). And getting rid of them would 
 be great news for those who care about keyword count.
 
 The complex types are different; the _only_ reason you'd remove them is 
 to reduce the keyword count. That's a completely different issue.

Of course, the fewness of keywords can be perceived as a measure of good language design. But decreasing the number of keywords artificially doesn't make any language better. "Have as few keywords as practical, but NO fewer than that!"
Jan 08 2008
next sibling parent Don Clugston <dac nospam.com.au> writes:
Georg Wrede wrote:
 Don Clugston wrote:
 Georg Wrede wrote:

 Getting rid of them will release 6 keywords, and make the core 
 language simpler.

Now, this is the one subject that gets me downright ballistic. During the (some six) years I've been a part of D, I have constantly had a problem with this keyword number issue.

 As a result of this all, I'm definitely of the opinion that "one concept
 warrants one word", and that "the same word for different purposes is
 poison", and that "the same concept with different words is poison".

 (Do I have to say "const", anybody???")

There's a funny thing about this situation. Here's the background: * I argued (on the ng) against overloading the 'enum' keyword to mean manifest constants. * Andrei emailed me, basically saying that we need to keep the keyword count down.

This should NEVER be an isolated goal. Rather, it should just be the natural result of good language design. And only that. BASIC and Brainf**k have fewer keywords than D, but I wouldn't call them better than D.
 * I responded that if we want to get the keyword count down, an 
 obvious way to do it would be to remove the pure imaginary types.
 * Andrei discussed this with Walter.

 Essentially, I don't think that pure imaginary types belong in the 
 language (not even in a standard library). And getting rid of them 
 would be great news for those who care about keyword count.

 The complex types are different; the _only_ reason you'd remove them 
 is to reduce the keyword count. That's a completely different issue.

Of course, the fewness of keywords can be perceived as a measure of good language design. But decreasing the number of keywords artificially doesn't make any language better.

I agree completely. It's the typical problem you get with any indirect metric. Keyword count can be a measure of language complexity, but you can fall into the horrible trap of making the language more complicated in order to reduce the number of keywords. It becomes a useless metric if you start to optimise for it.
 "Have as few keywords as practical, but NO fewer than that!"

Jan 08 2008
prev sibling parent Russell Lewis <webmaster villagersonline.com> writes:
Georg Wrede wrote:
 Of course, the fewness of keywords can be perceived as a measure of good 
 language design. But decreasing the number of keywords artificially 
 doesn't make any language better.
 
 "Have as few keywords as practical, but NO fewer than that!"

I wrote a programming language that used only 26 keywords: a,b,c,d... Of course, each keyword had a subtly different meaning depending on its context... ;)
Jan 09 2008
prev sibling next sibling parent reply naryl <cy ngs.ru> writes:
On Mon, 07 Jan 2008 09:00:38 +0300, Walter Bright  
<newshound1 digitalmars.com> wrote:

 The issue comes up now and then about why have complex and imaginary  
 types, rather than using structs? All but one of the advantages of  
 having them be core types can be addressed with advancing compiler  
 technology. Getting rid of them will release 6 keywords, and make the  
 core language simpler. Given the increasing complexity of D, this will  
 help.

 The remaining advantage is that of imaginary literals, i.e. the i  
 postfix:

 	3 + 5i

 Assuming we solve the literal problem, existing code would only need to  
 add:

 	import std.complex;

 to acquire complex and imaginary types.

"No issue left behind" Why don't we remove or at least shorten foreach_reverse too?
Jan 10 2008
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
naryl:
 Why don't we remove or at least shorten foreach_reverse too?

Removing: -1. It's actually useful (I'd like to see more iteration constructs, not less). Shortening: it's long, so maybe yes, if you/someons find(s) something better. Do you have some suggestions? Bye, bearophile
Jan 10 2008
next sibling parent reply Matti Niemenmaa <see_signature for.real.address> writes:
bearophile wrote:
 naryl:
 Why don't we remove or at least shorten foreach_reverse too?

Removing: -1. It's actually useful (I'd like to see more iteration constructs, not less). Shortening: it's long, so maybe yes, if you/someons find(s) something better. Do you have some suggestions?

Ever since the language got the ability to use delegates as the foreach aggregate, there has been no need for foreach_reverse. Ironically enough, that's the same release foreach_reverse was added (0.170). Arrays should just have a built-in .reverseview (or whatever) property which returns a delegate for iterating over the array in reverse order. And add .sortedview while you're at it. -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Jan 11 2008
next sibling parent Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Matti Niemenmaa wrote:
 bearophile wrote:
 naryl:
 Why don't we remove or at least shorten foreach_reverse too?

Removing: -1. It's actually useful (I'd like to see more iteration constructs, not less). Shortening: it's long, so maybe yes, if you/someons find(s) something better. Do you have some suggestions?

Ever since the language got the ability to use delegates as the foreach aggregate, there has been no need for foreach_reverse. Ironically enough, that's the same release foreach_reverse was added (0.170). Arrays should just have a built-in .reverseview (or whatever) property which returns a delegate for iterating over the array in reverse order. And add .sortedview while you're at it.

And the only reason this isn't how its done is because dmd is unable to inline functions containing loops, thus foreach_reverse is the faster solution for built in arrays. -- Oskar
Jan 11 2008
prev sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Matti Niemenmaa wrote:
 Arrays should just have a built-in .reverseview (or whatever) property 
 which returns a delegate for iterating over the array in reverse order.
 
 And add .sortedview while you're at it.
 

+1. I really like this idea (if the inlining thing could be worked out).
Jan 11 2008
prev sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
naryl wrote:
 On Fri, 11 Jan 2008 04:03:46 +0300, bearophile 
 <bearophileHUGS lycos.com> wrote:
 
 naryl:
 Why don't we remove or at least shorten foreach_reverse too?

Removing: -1. It's actually useful (I'd like to see more iteration constructs, not less). Shortening: it's long, so maybe yes, if you/someons find(s) something better. Do you have some suggestions? Bye, bearophile

Let me quote Regan Heath: In article <opsmol1osx23k2f5 ally>, Regan Heath says...
 Does the term "foreach" imply any direction forward or backward? To me it
 doesn't. I realise it's used in other languages, the same as in D, so it
 has a commonly understood meaning.

 I think the options are:

 - leave foreach, invent a backwards term i.e. foreach_r.
 - invent new terms, one for forward, one for backward.
 - add the ability to specify the 'step' in foreach
 Regan

I agree with Regan. foreach don't need to imply any direction. Compiler must be able to parallelize it. For iteration constructs with implied direction my favourite is: foreach(forward) foreach(reverse) foreach(forward, firstEvenThenOdd) etc -- naryl

IMHO both foreach_reverse *and* foreach are ugly hacks and should be removed in D2. let me quote a related post:
 Sorry, to use the web interface to the newsgroup..

 This is an old (1993), but I hope related, discussion:

 Iterators: Signs of Weakness in Object-Oriented Languages
 http://home.pipeline.com/~hbaker1/Iterator.html

 - Paul

I think the solution should be a more general approach: a) use the functional approach with mapping and filter functions. According to the article in the quote such an implementation requires full closures which D 2.x has. this could be implemented in a library. so with that approach I could use the ruby way of: --- collection.each BlockOfCode or in D: collection.each ((item a) {...code...}); or with free functions: map(item[], (item a) {...code...}); --- b) for iterations where order is important, maybe implement generators (also mentioned in the above article). just my 2 cents. --Yigal
Jan 11 2008
next sibling parent Russell Lewis <webmaster villagersonline.com> writes:
Yigal Chripun wrote:
 IMHO both foreach_reverse *and* foreach are ugly hacks and should be 
 removed in D2.

I can see how we might choose to remove foreach_reverse (assuming that DMD can properly inline loops...another post suggested that it currently could not). However, I wanted to speak up in favor of foreach(): IMHO, it is an exceptionally useful tool because it provides auto-translation of the "continue", "break", and "return" semantics. Can you imagine the syntax required to emulate a return out of a loop body if foreach didn't do it for you? Sure, you could do it by hand, but it'd be very ugly. foreach() is such a common paradigm that I think that the syntax sugar is worth it. MHO.
Jan 11 2008
prev sibling parent reply Pragma <ericanderton nospam.yahoo.com> writes:
Yigal Chripun Wrote:

 I think the solution should be a more general approach:
 a) use the functional approach with mapping and filter functions. 
 According to the article in the quote such an implementation requires
 full closures which D 2.x has.
 this could be implemented in a library.
 so with that approach I could use the ruby way of:
 ---
 collection.each BlockOfCode
 
 or in D:
 
 collection.each ((item a) {...code...});
 
 or with free functions:
 
 map(item[], (item a) {...code...});
 ---
 b) for iterations where order is important, maybe implement generators 
 (also mentioned in the above article).
 
 just my 2 cents.
 
 --Yigal
 

IMO, were D conceived as a functional language, or one that was far more FP oriented, this probably would have been included early on. True closures are going to open up a *lot* of possibilities. However, D is much more procedural in it's grammar to make the outright removal of foreach() a good idea; I think it's kind of part of D's heritage and DNA to an extent. Comfort, familiarity and ease-of-use with foreach() trumps normalizing the language in favor of a more general construct. Also D has a foreach() construct that is hands-down better than what Java has, so why throw it away? That said, you're right about the library approach. I'd love to use that in my code when/if the opportunity presents itself. Python's map() has spoiled me so.
Jan 11 2008
parent bearophile <bearophileHUGS lycos.com> writes:
Pragma:
True closures are going to open up a *lot* of possibilities.

I'm waiting to see the first one bold enough to define and use monads with the new closures of D ;-) (While I am not waiting to see the first Y). Bye, bearophile
Jan 11 2008
prev sibling parent naryl <cy ngs.ru> writes:
On Fri, 11 Jan 2008 04:03:46 +0300, bearophile <bearophileHUGS lycos.com>  
wrote:

 naryl:
 Why don't we remove or at least shorten foreach_reverse too?

Removing: -1. It's actually useful (I'd like to see more iteration constructs, not less). Shortening: it's long, so maybe yes, if you/someons find(s) something better. Do you have some suggestions? Bye, bearophile

Let me quote Regan Heath: In article <opsmol1osx23k2f5 ally>, Regan Heath says...
 Does the term "foreach" imply any direction forward or backward? To me it
 doesn't. I realise it's used in other languages, the same as in D, so it
 has a commonly understood meaning.

 I think the options are:

 - leave foreach, invent a backwards term i.e. foreach_r.
 - invent new terms, one for forward, one for backward.
 - add the ability to specify the 'step' in foreach
 Regan

I agree with Regan. foreach don't need to imply any direction. Compiler must be able to parallelize it. For iteration constructs with implied direction my favourite is: foreach(forward) foreach(reverse) foreach(forward, firstEvenThenOdd) etc -- naryl
Jan 10 2008
prev sibling parent reply Pablo Ripolles <in-call gmx.net> writes:
Walter Bright Wrote:

 The issue comes up now and then about why have complex and imaginary 
 types, rather than using structs? All but one of the advantages of 
 having them be core types can be addressed with advancing compiler 
 technology. Getting rid of them will release 6 keywords, and make the 
 core language simpler. Given the increasing complexity of D, this will help.
 
 The remaining advantage is that of imaginary literals, i.e. the i postfix:
 
 	3 + 5i
 
 Assuming we solve the literal problem, existing code would only need to add:
 
 	import std.complex;
 
 to acquire complex and imaginary types.

Hello all, although perhaps a bit late the following are my points of view. * Presumably D has a very interesting future in numerics. As you clearly state in the Foreword of the recently published 'Learn to Tango with D', there is a gaping hole. An moreover the need for performance and flexibility. Definitely, D is a much better way to tackle the increasing complexity of the next coming numerical projects. * There is no numerics in D without scientists and engineers programming it in D. In this numerical programming field, as in many other aspects of life, there is the classic approach and the more vanguardist one. In the classic and conservative branch people use the good old Fortran, perhaps recycled into Fortran95: "runs fast, it's easy to learn and we know it well". In the more vanguardist and progressive branch people use the hardcore C++: "here is where the real power is", perhaps a mixture of Python and Fortran. Probably formal education tends to be much less interdisciplinary than many of us wish it would be... The people from engineering dedicated to numerics know their fluid dynamics quite well, but in general the C++ not that well. The people from informatics dedicated to numerics know their C++ quite well, but in general the fluid dynamics not that well. All this is quite reasonable... both worlds are overly complex! fluid dynamics is the task, the programming language is the tool, whose complexity can we reduce? probably both... Among other things this invites us to design a better programming language. Fortran people that are doing mix programming such as Python-Fortran will migrate to D, however the rest of the Fortran programmers might have prejudices... simplistic judgements are not uncommon: "How come D is supposed to be the promised land without the complex intrinsic (core) type?", "That's a step backwards!", "What about standardization? " these have been classic arguments from Fortran programmers against C++ in numerics. The same goes for the intrinsic (core) array syntax introduced in Fortran90. So in this context, although standardization might be a weak argument it has been used strongly. * As Don said, game programmers might wonder why complex deserve to be in the core language and not quaternions. I agree, however that reasoning is due to the biased criterion of a game programmer. I would dare to say that the reasons why complex numbers are studied in any basic course of mathematics (along with integers and real numbers) and not the quaternions are the same as why they might be a better candidate to be in the core language. * Again as Don said, the set of imaginary numbers has no practical use in mathematics. As Bill mentioned there is no set of the imaginary numbers defined in mathematics. Why should it be in a programming language? This would definitely strike a numerical analyst very weird! I think that if the type of complex numbers is in the core language it should respect the mathematical foundations, so why do we need the set of imaginary numbers? that definitely needs a redesign! * Complex numbers are very useful in numerics. They may be used in many situations as if they were reals. They may reduce differential operations to algebraic ones: solving a linear set of differential equations in the real field reduces to solving a linear set of algebraic equations in the complex field. This is just to mention a few... I am not claiming this is an argument for complex numbers to be in the core language as long as performance holds the same. Well, i think that is about all i wanted to say... Cheers!
Jan 14 2008
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Pablo Ripolles:
 Fortran people that are doing mix programming such as Python-Fortran
 will migrate to D,

Predicting the future isn't easy. Maybe they will migrate to Python + Cython (derived from Pyrex), or to Fortress (a neat language from Sun that I think D may learn something from), etc. And existing Pyd, they may even migrate to Python + Pyd + D ;-) Bye, bearophile
Jan 14 2008
parent Pablo Ripolles <in-call gmx.net> writes:
bearophile Wrote:

 Pablo Ripolles:
 Fortran people that are doing mix programming such as Python-Fortran
 will migrate to D,

Predicting the future isn't easy. Maybe they will migrate to Python + Cython (derived from Pyrex), or to Fortress (a neat language from Sun that I think D may learn something from), etc. And existing Pyd, they may even migrate to Python + Pyd + D ;-) Bye, bearophile

Indeed, predicting the future was not my intention. Yeah! that was an oversimplification... perhaps I should have written "might" or "would" instead of "will". Thanks!
Jan 14 2008
prev sibling parent reply Don Clugston <dac nospam.com.au> writes:
Pablo Ripolles wrote:
 Walter Bright Wrote:
 
 The issue comes up now and then about why have complex and imaginary 
 types, rather than using structs? All but one of the advantages of 
 having them be core types can be addressed with advancing compiler 
 technology. Getting rid of them will release 6 keywords, and make the 
 core language simpler. Given the increasing complexity of D, this will help.

 The remaining advantage is that of imaginary literals, i.e. the i postfix:

 	3 + 5i

 Assuming we solve the literal problem, existing code would only need to add:

 	import std.complex;

 to acquire complex and imaginary types.

Hello all, although perhaps a bit late the following are my points of view. * Presumably D has a very interesting future in numerics. As you clearly state in the Foreword of the recently published 'Learn to Tango with D', there is a gaping hole. An moreover the need for performance and flexibility. Definitely, D is a much better way to tackle the increasing complexity of the next coming numerical projects. * There is no numerics in D without scientists and engineers programming it in D. In this numerical programming field, as in many other aspects of life, there is the classic approach and the more vanguardist one. In the classic and conservative branch people use the good old Fortran, perhaps recycled into Fortran95: "runs fast, it's easy to learn and we know it well". In the more vanguardist and progressive branch people use the hardcore C++: "here is where the real power is", perhaps a mixture of Python and Fortran. Probably formal education tends to be much less interdisciplinary than many of us wish it would be... The people from engineering dedicated to numerics know their fluid dynamics quite well, but in general the C++ not that well. The people from informatics dedicated to numerics know their C++ quite well, but in general the fluid dynamics not that well. All this is quite reasonable... both worlds are overly complex! fluid dynamics is the task, the programm

 
 * As Don said, game programmers might wonder why complex deserve to be in the
core language and not quaternions.  I agree, however that reasoning is due to
the biased criterion of a game programmer.  I would dare to say that the
reasons why complex numbers are studied in any basic course of mathematics
(along with integers and real numbers) and not the quaternions are the same as
why they might be a better candidate to be in the core language.

Yes, my comment wasn't really fair. Complex numbers are fundamental to mathematics in a way that quaternions are not. But, imagine if quaternions were included, and treated in the same way as cdouble/idouble. We'd need quaternions, imaginary, complex, real, root_i, i*root_i, (root_i+imaginary), (root_i+i*root_i), (imaginary+i*root_i), (root_i+imaginary+i*root_i). (real +root_i+imaginary), (real +root_i+i*root_i), (real + imaginary+i*root_i). That's 12 types * { float, double, real} = 36 types! It's just not a viable approach.
 * Again as Don said, the set of imaginary numbers has no practical use in
mathematics.  As Bill mentioned there is no set of the imaginary numbers
defined in mathematics.  Why should it be in a programming language? This would
definitely strike a numerical analyst very weird!  I think that if the type of
complex numbers is in the core language it should respect the mathematical
foundations, so why do we need the set of imaginary numbers? that definitely
needs a redesign!

Imaginary numbers were included in D because they are in C99. Why are they in C99? It's because of a really obscure situation. (a.re + a.im * 1i)*(0.0 + b.im * 1i) is not the same as (a.re + a.im * 1i)*(b.im * 1i) if a.im or a.re is infinity. In the version where b.re is 0.0, a NaN is created, instead of the correct answer of 0. Ultimately this happens because 0.0 can mean either exactly 0, or 'too small to represent' (an underflow). As far as I can tell, D can avoid the need for a pure imaginary type, because *D guarantees constant folding, whereas C does not*. If constant folding is guaranteed, then with any compile-time complex constant, you know if it is a zero, or just an underflow. The problematic multiply-by-approximately zero can be eliminated -- it is known that it is a multiply-by-exactly zero. So we don't need the C99 hack of creating an entirely different type.
 * Complex numbers are very useful in numerics.  They may be used in many
situations as if they were reals.  They may reduce differential operations to
algebraic ones: solving a linear set of differential equations in the real
field reduces to solving a linear set of algebraic equations in the complex
field.  This is just to mention a few...  I am not claiming this is an argument
for complex numbers to be in the core language as long as performance holds the
same.
 
 Well, i think that is about all i wanted to say...
 
 Cheers!

Jan 14 2008
next sibling parent Pablo Ripolles <in-call gmx.net> writes:
Don Clugston Wrote:

 Pablo Ripolles wrote:
 Walter Bright Wrote:
 
 The issue comes up now and then about why have complex and imaginary 
 types, rather than using structs? All but one of the advantages of 
 having them be core types can be addressed with advancing compiler 
 technology. Getting rid of them will release 6 keywords, and make the 
 core language simpler. Given the increasing complexity of D, this will help.

 The remaining advantage is that of imaginary literals, i.e. the i postfix:

 	3 + 5i

 Assuming we solve the literal problem, existing code would only need to add:

 	import std.complex;

 to acquire complex and imaginary types.

Hello all, although perhaps a bit late the following are my points of view. * Presumably D has a very interesting future in numerics. As you clearly state in the Foreword of the recently published 'Learn to Tango with D', there is a gaping hole. An moreover the need for performance and flexibility. Definitely, D is a much better way to tackle the increasing complexity of the next coming numerical projects. * There is no numerics in D without scientists and engineers programming it in D. In this numerical programming field, as in many other aspects of life, there is the classic approach and the more vanguardist one. In the classic and conservative branch people use the good old Fortran, perhaps recycled into Fortran95: "runs fast, it's easy to learn and we know it well". In the more vanguardist and progressive branch people use the hardcore C++: "here is where the real power is", perhaps a mixture of Python and Fortran. Probably formal education tends to be much less interdisciplinary than many of us wish it would be... The people from engineering dedicated to numerics know their fluid dynamics quite well, but in general the C++ not that well. The people from informatics dedicated to numerics know their C++ quite well, but in general the fluid dynamics not that well. All this is quite reasonable... both worlds are overly complex! fluid dynamics is the task, the programm

 
 * As Don said, game programmers might wonder why complex deserve to be in the
core language and not quaternions.  I agree, however that reasoning is due to
the biased criterion of a game programmer.  I would dare to say that the
reasons why complex numbers are studied in any basic course of mathematics
(along with integers and real numbers) and not the quaternions are the same as
why they might be a better candidate to be in the core language.

Yes, my comment wasn't really fair. Complex numbers are fundamental to mathematics in a way that quaternions are not. But, imagine if quaternions were included, and treated in the same way as cdouble/idouble. We'd need quaternions, imaginary, complex, real, root_i, i*root_i, (root_i+imaginary), (root_i+i*root_i), (imaginary+i*root_i), (root_i+imaginary+i*root_i). (real +root_i+imaginary), (real +root_i+i*root_i), (real + imaginary+i*root_i). That's 12 types * { float, double, real} = 36 types! It's just not a viable approach.
 * Again as Don said, the set of imaginary numbers has no practical use in
mathematics.  As Bill mentioned there is no set of the imaginary numbers
defined in mathematics.  Why should it be in a programming language? This would
definitely strike a numerical analyst very weird!  I think that if the type of
complex numbers is in the core language it should respect the mathematical
foundations, so why do we need the set of imaginary numbers? that definitely
needs a redesign!

Imaginary numbers were included in D because they are in C99. Why are they in C99? It's because of a really obscure situation. (a.re + a.im * 1i)*(0.0 + b.im * 1i) is not the same as (a.re + a.im * 1i)*(b.im * 1i) if a.im or a.re is infinity. In the version where b.re is 0.0, a NaN is created, instead of the correct answer of 0. Ultimately this happens because 0.0 can mean either exactly 0, or 'too small to represent' (an underflow).

 As far as I can tell, D can avoid the need for a pure imaginary type, because
*D 
 guarantees constant folding, whereas C does not*. If constant folding is 
 guaranteed, then with any compile-time complex constant, you know if it is a 
 zero, or just an underflow. The problematic multiply-by-approximately zero can 
 be eliminated -- it is known that it is a multiply-by-exactly zero. So we
don't 
 need the C99 hack of creating an entirely different type.
 
 * Complex numbers are very useful in numerics.  They may be used in many
situations as if they were reals.  They may reduce differential operations to
algebraic ones: solving a linear set of differential equations in the real
field reduces to solving a linear set of algebraic equations in the complex
field.  This is just to mention a few...  I am not claiming this is an argument
for complex numbers to be in the core language as long as performance holds the
same.
 
 Well, i think that is about all i wanted to say...
 
 Cheers!


Jan 14 2008
prev sibling parent Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Don Clugston wrote:

 Imaginary numbers were included in D because they are in C99. Why are 
 they in C99?
 It's because of a really obscure situation.
 (a.re + a.im * 1i)*(0.0 + b.im * 1i)
 is not the same as (a.re + a.im * 1i)*(b.im * 1i)
 
 if a.im or a.re is infinity. In the version where b.re is 0.0, a NaN is 
 created, instead of the correct answer of 0.
 Ultimately this happens because 0.0 can mean either exactly 0, or 'too 
 small to represent' (an underflow).

Thank you for the enlightening information.
 As far as I can tell, D can avoid the need for a pure imaginary type, 
 because *D guarantees constant folding, whereas C does not*. If constant 
 folding is guaranteed, then with any compile-time complex constant, you 
 know if it is a zero, or just an underflow. The problematic 
 multiply-by-approximately zero can be eliminated -- it is known that it 
 is a multiply-by-exactly zero. So we don't need the C99 hack of creating 
 an entirely different type.

But since D doesn't guarantee inlining, I guess there would still be an issue with functions that today are overloaded for the imaginary types. -- Oskar
Jan 15 2008