November 08, 2006
Jarrett Billingsley wrote:
> "David Qualls" <davidlqualls@yahoo.com> wrote in message news:eirqai$he$1@digitaldaemon.com...
> 
>> So, is it possible to use templates to define generic binary
>> operators; like 'and' and 'or', or a unary operator like 'not'?
> 
> Not like the way you'd use the iso646 ones.  It'd be really unnatural:
> 
> if(not(and(a, or(b, c))))
>     ...

I'm a Lisp user you insensitive clod!  That looks perfectly natural to me!  :-)


> T max(T)(T a, T b)
> {
>     return (a > b) ? a : b;
> }
> 
> Which is pretty readable to me, and probably covers most of the use cases. Most of that conversion stuff in Sean's implementation is probably type trait stuff which would best belong in std.traits (when it comes out).. 

But it's very annoying in C++.

   float x = 17;
   std::max(x,0); // error! which max do you mean - float or int?
   std::max(x,0.0); // error! which max do you mean - float or double?
   std::max(x,0.0f); // ok, both float

Especially annoying for containers parameterized by numeric type. Then you don't know what to use for the literal you're comparing against, so you've got to use a cast.

   T x = 17;  // could be float,double,real,int etc
   std::max(x, cast(T)0); // ugh.

--bb
November 08, 2006
== Quote from mike (vertex@gmx.at)'s article
> Hmm, if you really want to you could run D code through CPP
anyway befor=
> e  =
> passing it to DMD. Shouldn't be that hard to make a script for
that.
> -Mike
> -- =
> Erstellt mit Operas revolution=E4rem E-Mail-Modul:
http://www.opera.com/=
> mail/

I was actually thinking about doing just that.  Still though, the real competitor here is either Basic, Fortran, or C with sufficient macros that I can take my code to a board room and explain it to intelligent people who are not programmers.  Yes, I can write in pseudo code for them, but then there's always the question of whether I did the translation from pseudo into D correctly.  Once I digress to using a custom script or program to preprocess the text before submitting it to the compiler, I'm building a tool chain that: a)won't work with a standard compiler distribution (you also have to have my preprocessing tool along with it), b)is subject to being rejected due to complexity.

An alternate approach I might take is to simply write psuedo code for every single line of code:

      //if BOTH y and z are true.
        if( y && z ) // then
        {

which I think to most of us seems like a waste of keystrokes, and a bit cluttered.

David

November 08, 2006
Bill Baxter wrote:
> 
> Especially annoying for containers parameterized by numeric type. Then you don't know what to use for the literal you're comparing against, so you've got to use a cast.
> 
>    T x = 17;  // could be float,double,real,int etc
>    std::max(x, cast(T)0); // ugh.

In all fairness, this can be rewritten as:

    std::max<T>( x, 0 );

By the way, I had to add casts to my min/max functions to allow class types to be comparable.  For example:

    class A
    {
      int opCmp( A rhs )      { ... }
      int opCmp( Object rhs ) { ... }
    }
    class B : A {}
    class C : A {}

    A a = new A;
    B b = new B;
    C c = new C;

    min( a, b ); // 1
    min( b, a ); // 2
    min( b, c ); // 3

In cases 1 and 2, opCmp(A) should be called, but the call is ambiguous since b is convertible to both A and Object.  And in case 3, opCmp(Object) should be called, since the mechanism isn't smart enough to figure out that b and c have a common user-defined parent.  Casting fixes both of these, though it pained me to add it :-)

Sean
November 08, 2006
Sean Kelly wrote:
> Bill Baxter wrote:
>> Sean Kelly wrote:
>>> Bill Baxter wrote:
>>>
>>>> Is there a generic 'max' function anywhere in phobos?
>>>> The closest I could find was std.math.fmax().
>>>
>>>
>>> Not that works for all input types, as far as I know.  However, something like the code below should work.  This is off the top of my head so it may have bugs, but it's a general idea of what such a template function may need to do.
>>
>> Great!  How do we get it into std.math?
>>
>> Here's one with the typos fixed and unittests:
> 
> I rewrote the code to work a bit better and added some more tests. However, I think it should probably error when comparing a signed and unsigned integer type.  At the moment, it accepts this and the choice of return type is somewhat arbitrary.  Also, I haven't tested interfaces and am not sure they should be comparable anyway, but I added support for them for the heck of it.  I'd play with it a bit more but I'm tired and bed is calling :-)

Great.  About signed types, I think

   auto c = max(a,b)

should pick the same type for c that the compiler would pick for

   auto c = a+b;

--bb
November 09, 2006
Sean Kelly wrote:
> Bill Baxter wrote:
>>
>> Especially annoying for containers parameterized by numeric type. Then you don't know what to use for the literal you're comparing against, so you've got to use a cast.
>>
>>    T x = 17;  // could be float,double,real,int etc
>>    std::max(x, cast(T)0); // ugh.
> 
> In all fairness, this can be rewritten as:
> 
>     std::max<T>( x, 0 );

The cast is not so bad in real C++ either:

      std::max(x, T(0));

But my point was just that the extra information is not necessary for the macro version.  The intended meaning of max(x,0) is clear enough to the reader, so the compiler should be able to handle it without complaining, too.

--bb
November 09, 2006
== Quote from Bill Baxter (dnewsgroup@billbaxter.com)'s article

> But my point was just that the extra information is not
necessary for
> the macro version.  The intended meaning of max(x,0) is clear
enough to
> the reader, so the compiler should be able to handle it without
> complaining, too.
> --bb

EXACTLY!  I also think you (mostly) nailed it with

> About signed types, I think
>     auto c = max(a,b)
> should pick the same type for c that the compiler would pick for
>     auto c = a+b;

except I don't think max(10U , -1) should return -1 cast to an
unsigned!
November 09, 2006
David Qualls wrote:
> == Quote from Bill Baxter (dnewsgroup@billbaxter.com)'s article
> 
> 
>>But my point was just that the extra information is not
> 
> necessary for
> 
>>the macro version.  The intended meaning of max(x,0) is clear
> 
> enough to
> 
>>the reader, so the compiler should be able to handle it without
>>complaining, too.
>>--bb
> 
> 
> EXACTLY!  I also think you (mostly) nailed it with
> 
> 
>>About signed types, I think
>>    auto c = max(a,b)
>>should pick the same type for c that the compiler would pick for
>>    auto c = a+b;
> 
> 
> except I don't think max(10U , -1) should return -1 cast to an
> unsigned!

Oof.  No it should not.  But the macro would fail there too.  At least in D, (10U<-1) evaluates to true.


--bb
November 09, 2006
David Qualls wrote:
> == Quote from Bill Baxter (dnewsgroup@billbaxter.com)'s article
> 
>> But my point was just that the extra information is not
> necessary for
>> the macro version.  The intended meaning of max(x,0) is clear
> enough to
>> the reader, so the compiler should be able to handle it without
>> complaining, too.
>> --bb
> 
> EXACTLY!  I also think you (mostly) nailed it with
> 
>> About signed types, I think
>>     auto c = max(a,b)
>> should pick the same type for c that the compiler would pick for
>>     auto c = a+b;
> 
> except I don't think max(10U , -1) should return -1 cast to an
> unsigned!

The addition promotion rules for integers are essentially as follows:

int + uint = uint
uint + long = long
(anything smaller than int) + (anything smaller than int) = int

It would be easy enough to simply use typeof(T.init + U.init) for concrete types and throw out a bunch of static ifs, but I'm not sure if integer promotion is desired here.  Suggestions?


Sean
November 10, 2006

David Qualls wrote:
> == Quote from Bill Baxter (dnewsgroup@billbaxter.com)'s article
> 
>> But my point was just that the extra information is not
> necessary for
>> the macro version.  The intended meaning of max(x,0) is clear
> enough to
>> the reader, so the compiler should be able to handle it without
>> complaining, too.
>> --bb
> 
> EXACTLY!  I also think you (mostly) nailed it with
> 
>> About signed types, I think
>>     auto c = max(a,b)
>> should pick the same type for c that the compiler would pick for
>>     auto c = a+b;
> 
> except I don't think max(10U , -1) should return -1 cast to an
> unsigned!

One thing I did when I was playing around with some MMX code was write a template that figured out the "expression-safe" type of something. Basically, it was the type for which any expression involving the base type could be contained in.  I used it to ensure that stuff like int+int wouldn't overflow.

You could always say that when combining a signed and unsigned type, take the signed type large enough to hold either.  If the user has a problem with having to cast it back, tell him to use arguments of the same type, damnit!

"But I don't *wanna*!"
"Tough.  Don't wanna deal with types?  Go program in PHP."
"I'll behave..."

	-- Daniel

-- 
Unlike Knuth, I have neither proven or tried the above; it may not even make sense.

v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP  http://hackerkey.com/
November 14, 2006
On Wed, 08 Nov 2006 05:48:58 -0800, Sean Kelly <sean@f4.ca> wrote:

> David Qualls wrote:
>>  So, is it possible to use templates to define generic binary
>> operators; like 'and' and 'or', or a unary operator like 'not'?
>
> They're in the C++ standard library, so I don't see why not.
>
>> After looking at the mass of code it takes to implement a simple
>> generic max() or min() function in D, I'm really starting to pine
>> for my C preprocessor...
>>  #define max(a,b) ((a)>(b)?(a):(b))
>>  Yeah, I know it breaks if a or b include side effects, but it's
>> extremely READABLE!
>
> There has been a lot of work done in the C++ community to produce a template function that is as functional as this simple macro.  In fact, I think Andrei actually wrote a series of articles on it.  I think we can do better in D because of the improved compile-time type information, but it's difficult to match the simplicity of macro code replacement.
>
>
> Sean


Blech!  I do not find C/C++ macros readable!  This small sample is hardly representative of the abuse of the preprocessor that exists in most of C/C++ land and is hardly an argument for having a PP in D.  Abuse of the CPP has made a horrid mess of code and makes it impossible to determine what is /really/ going on in there (I especially resent macros in macros in macros :P ).  I, for one, don't miss the preprocessor's absence from D.  D compile-time features are gradually progressing to the state where almost all CPP functionality is possible, anyway.  Those that are addicted to the CPP might do better to take a break from it and start experimenting with the D system.

Sure the CPP may inline things efficiently, but it's really just a poor man's templating system... a hack that's gone horribly wayward since long ago.

Oh... that feels better.  It seems I periodically have to bash the CPP... at least once a year, at least. :)

-JJR