Jump to page: 1 2 3
Thread overview
max() in phobos?
Nov 06, 2006
Bill Baxter
Nov 06, 2006
Sean Kelly
Nov 07, 2006
Bill Baxter
Nov 08, 2006
Sean Kelly
Nov 08, 2006
Bill Baxter
Re: max() in phobos, and English logic operators
Nov 08, 2006
David Qualls
Nov 08, 2006
Sean Kelly
Nov 08, 2006
Bill Baxter
Nov 08, 2006
Sean Kelly
Nov 09, 2006
Bill Baxter
Nov 09, 2006
David Qualls
Nov 09, 2006
Bill Baxter
Nov 09, 2006
Sean Kelly
Nov 10, 2006
Daniel Keep
Nov 08, 2006
Sean Kelly
Nov 14, 2006
John Reimer
Nov 14, 2006
David Qualls
Nov 14, 2006
John Reimer
Nov 08, 2006
mike
Nov 08, 2006
%u
Nov 14, 2006
Reiner Pope
Nov 07, 2006
Don Clugston
November 06, 2006
Is there a generic 'max' function anywhere in phobos?
The closest I could find was std.math.fmax().

Grepping Phobos, I find there is a generic max()/min() pair in called "std.math2".  Is math2 an official part of the library?  Can I count on it being there?  Or is that stuff that's slated to be moved into std.math eventually?

--bb
November 06, 2006
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.

/**
 * Returns the largest of the two supplied types, or the first type if
 * the sizes are identical.  If either type is an object then both must
 * be objects of either the same type or where one is a base class of
 * the other.  Interfaces are not supported.
 */
template largestOrConvertible( T, U )
{
    static if( is( T : Object ) || is( U : Object ) )
    {
        static assert( is( T : Object ) && is( U : Object ),
                       "Types incompatible." );

        static if( T : U )
            alias T largestOrConvertible;
        else static if( U : T )
            alias U largestOrConvertible;
        else static assert( false, "Object types must be related." );
    }
    else static if( is( T : Interface ) || is( U : Interface ) )
        static assert( false, "Interface types not yet supported." );
    else static if( T.sizeof < U.sizeof )
        alias U largestOf;  // concrete type, U larger
    else alias T largestOf; // concrete type, T larger or equal
}

template max( T, U )
{
    largestOrConvertible!(T,U) max( T t, U u )
    {
        return t > u ? t : u;
    }
}

template min( T, U )
{
    largestOrConvertible!(T,U) min( T t, U u )
    {
        return t < u ? t : u;
    }
}
November 07, 2006
Bill Baxter wrote:
> Is there a generic 'max' function anywhere in phobos?
> The closest I could find was std.math.fmax().
> 
> Grepping Phobos, I find there is a generic max()/min() pair in called "std.math2".  Is math2 an official part of the library?  Can I count on it being there?  Or is that stuff that's slated to be moved into std.math eventually?

It should be removed. Almost all of the worthwhile stuff in it was moved into std.math. The rest is obsolete, dating from the days before D had templates.
November 07, 2006
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:

/**
 * Returns the largest of the two supplied types, or the first type if
 * the sizes are identical.  If either type is an object then both must
 * be objects of either the same type or where one is a base class of
 * the other.  Interfaces are not supported.
 */
template largestOrConvertible( T, U )
{
    static if( is( T : Object ) || is( U : Object ) )
    {
        static assert( is( T : Object ) && is( U : Object ),
                       "Types incompatible." );

        static if( is(T : U) )
            alias T largestOrConvertible;
        else static if( is(U : T) )
            alias U largestOrConvertible;
        else static assert( false, "Object types must be related." );
    }
    else static if( is( T : Interface ) || is( U : Interface ) )
        static assert( false, "Interface types not yet supported." );
    else static if( T.sizeof < U.sizeof )
        alias U largestOf;  // concrete type, U larger
    else alias T largestOf; // concrete type, T larger or equal
}

template max( T, U )
{
    largestOrConvertible!(T,U).largestOf max( T t, U u )
    {
        return t > u ? t : u;
    }
}
template min( T, U )
{
    largestOrConvertible!(T,U).largestOf min( T t, U u )
    {
        return t < u ? t : u;
    }
}
unittest {
    int ismall=1, ibig=5;
    byte bsmall=1, bbig=5;
    float fsmall=1, fbig=5;
    double dsmall=1, dbig=5;
    assert(max(ibig,ismall)==ibig);
    assert(max(ismall,ibig)==ibig);
    assert(min(ibig,ismall)==ismall);
    assert(min(ismall,ibig)==ismall);

    assert(max(fbig,fsmall)==fbig);
    assert(max(fsmall,fbig)==fbig);
    assert(min(fbig,fsmall)==fsmall);
    assert(min(fsmall,fbig)==fsmall);

    assert(min(dsmall,fbig)==dsmall);
    assert(max(dsmall,fbig)==fbig);
    assert(min(dbig,fsmall)==fsmall);
    assert(max(dbig,fsmall)==dbig);

    assert( is(typeof(min(dsmall,fbig)) == double) );
    assert( is(typeof(max(dsmall,fbig)) == double) );
    assert( is(typeof(min(dbig,fsmall)) == double) );
    assert( is(typeof(max(dbig,fsmall)) == double) );

    assert( is(typeof(min(bsmall,ibig))==int) );
    assert( is(typeof(max(bsmall,ibig))==int) );
    assert( is(typeof(min(bbig,ismall))==int) );
    assert( is(typeof(max(bbig,ismall))==int) );
}

--bb
November 08, 2006
== Quote from Sean Kelly (sean@f4.ca)'s article
> 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.  ...
...
...much code omitted...
...
> template max( T, U )
> {
>      largestOrConvertible!(T,U) max( T t, U u )
>      {
>          return t > u ? t : u;
>      }
> }
> template min( T, U )
> {
>      largestOrConvertible!(T,U) min( T t, U u )
>      {
>          return t < u ? t : u;
>      }
> }

So, is it possible to use templates to define generic binary operators; like 'and' and 'or', or a unary operator like '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! (And back on my old soap-box, even FORTRAN and Basic include English binary logic operators ;-)

DQ
November 08, 2006
"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))))
    ...

> 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! (And back on my old soap-box, even FORTRAN and Basic include English binary logic operators ;-)

Well, if you make the max function a bit less generic, restricting it to just one input type, it becomes

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)..


November 08, 2006
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 :-)


template commonBaseTypeOf( T, U )
{
    static assert( ( is( T == class )     && is( U == class ) ) ||
                   ( is( T == interface ) && is( U == interface ) ),
                   "Supplied types are not siblings." );

    static if( is( T : U ) )
        alias U commonBaseTypeOf;
    else static if( is( U : T ) )
        alias T commonBaseTypeOf;
    else static if( is( T == class ) )
        alias Object commonBaseTypeOf;
    else
        static assert( false, "Interfaces have no generic parent." );
}

template bestCommonTypeOf( T, U )
{
    static if( is( T == class )     || is( U == class ) ||
               is( T == interface ) || is( U == interface ) )
    {
        alias commonBaseTypeOf!( T, U ) bestCommonTypeOf;
    }
    else static if( is( T : U ) && is( U : T ) )
    {
        static if( T.sizeof >= U.sizeof )
            alias T bestCommonTypeOf;
        else
            alias U bestCommonTypeOf;
    }
    else static if( is( U : T ) )
        alias T bestCommonTypeOf;
    else static if( is( T : U ) )
        alias U bestCommonTypeOf;
    else
        static assert( false, "Unable to find common type." );
}

template min( T, U )
{
    bestCommonTypeOf!(T, U) min( T t, U u )
    {
        alias bestCommonTypeOf!(T, U) rt;
        if( cast(rt) t < cast(rt) u )
            return t;
        return u;
    }
}

template max( T, U )
{
    bestCommonTypeOf!(T, U) max( T t, U u )
    {
        alias bestCommonTypeOf!(T, U) rt;
        if( cast(rt) t > cast(rt) u )
            return t;
        return u;
    }
}

unittest
{
    int ismall=1, ibig=5;
    byte bsmall=1, bbig=5;
    float fsmall=1, fbig=5;
    double dsmall=1, dbig=5;
    assert(max(ibig,ismall)==ibig);
    assert(max(ismall,ibig)==ibig);
    assert(min(ibig,ismall)==ismall);
    assert(min(ismall,ibig)==ismall);

    assert(max(fbig,fsmall)==fbig);
    assert(max(fsmall,fbig)==fbig);
    assert(min(fbig,fsmall)==fsmall);
    assert(min(fsmall,fbig)==fsmall);

    assert(min(dsmall,fbig)==dsmall);
    assert(max(dsmall,fbig)==fbig);
    assert(min(dbig,fsmall)==fsmall);
    assert(max(dbig,fsmall)==dbig);

    assert( is(typeof(min(dsmall,fbig)) == double) );
    assert( is(typeof(max(dsmall,fbig)) == double) );
    assert( is(typeof(min(dbig,fsmall)) == double) );
    assert( is(typeof(max(dbig,fsmall)) == double) );

    assert( is(typeof(min(bsmall,ibig))==int) );
    assert( is(typeof(max(bsmall,ibig))==int) );
    assert( is(typeof(min(bbig,ismall))==int) );
    assert( is(typeof(max(bbig,ismall))==int) );

    class B
    {
        this( int v )
        {
            value = v;
        }

        int opCmp( B rhs )
        {
            return value - rhs.value;
        }

        int opCmp( Object rhs )
        {
            return opCmp( cast(B) rhs );
        }

        private int value;
    }

    class C : B
    {
        this( int v )
        {
            super( v );
        }
    }

    class D : B
    {
        this( int v )
        {
            super( v );
        }
    }

    // BUG? what to do about implicit signed-unsigned conversion?
    static assert( is( bestCommonTypeOf!( int, uint ) == int ) );
    static assert( is( bestCommonTypeOf!( uint, int ) == uint ) );

    static assert( is( bestCommonTypeOf!( byte, long ) == long ) );
    static assert( is( bestCommonTypeOf!( long, byte ) == long ) );
    static assert( is( bestCommonTypeOf!( long, float ) == float ) );
    static assert( is( bestCommonTypeOf!( float, long ) == float ) );
    static assert( is( bestCommonTypeOf!( float, real ) == real ) );
    static assert( is( bestCommonTypeOf!( cfloat, creal ) == creal ) );
    static assert( is( bestCommonTypeOf!( creal, cfloat ) == creal ) );

    static assert( is( bestCommonTypeOf!( B, C ) == B ) );
    static assert( is( bestCommonTypeOf!( C, B ) == B ) );
    static assert( is( bestCommonTypeOf!( C, D ) == Object ) );
    static assert( is( bestCommonTypeOf!( D, C ) == Object ) );

    B b = new B( 1 );
    C c = new C( 2 );
    D d = new D( 3 );

    assert( min( b, c ) == b );
    assert( max( b, c ) == c );
    assert( min( c, d ) == c );
    assert( max( c, d ) == d );
}
November 08, 2006
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
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))))
>     ...

Yup.  These are in C++ only to allow expressions to be built using template composition for use in algorithms.  And the result quickly gets annoyingly complex and hard to read.  Lambda expression are a much clearer replacement, which we have to some degree with lazy parameters and anonymous delegates.  By contrast, C++ uses fancy classes with cleverly overloaded operators and some global placeholders.  It works fairly well all things considered, but the code behind it is a bit much.

>> 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! (And back on my old soap-box, even FORTRAN and
>> Basic include English binary logic operators ;-)
> 
> Well, if you make the max function a bit less generic, restricting it to just one input type, it becomes
> 
> 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).. 

Agreed on both counts.  My template was really to avoid requiring the user to explicitly specify template type parameters of the types of a and b are different, to make min/max behave as close to the C macro as possible.


Sean
November 08, 2006
Am 08.11.2006, 06:35 Uhr, schrieb David Qualls <davidlqualls@yahoo.com>:

> 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))
>

Hmm, if you really want to you could run D code through CPP anyway before passing it to DMD. Shouldn't be that hard to make a script for that.

-Mike

-- 
Erstellt mit Operas revolutionärem E-Mail-Modul: http://www.opera.com/mail/
« First   ‹ Prev
1 2 3