www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - generic functions

reply orgoton <orgoton mindless.com> writes:
I've been trying to create a function that would receive a single variable of
any type, like a "abs" function, so that I won't have to code the same function
for "real" and "long" var types. What's the most straightforward way to do it?
I've seen templates at the D documentation, but those require me to instantiate
the function. Is there anyway to bypass this?
Apr 27 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
orgoton wrote:
 I've been trying to create a function that would receive a single variable of
any type, like a "abs" function, so that I won't have to code the same function
for "real" and "long" var types. What's the most straightforward way to do it?
I've seen templates at the D documentation, but those require me to instantiate
the function. Is there anyway to bypass this?

No, I don't think there's a good way to bypass this. D is a statically typed language, so a function needs to know the types of the arguments. --- // Note: doesn't handle byte.min, short.min, int.min and // long.min correctly because their positive values don't // fit into the corresponding type... :( // (This could be fixed by having abs() return the unsigned // variant of those types, but I don't feel like typing // that much) T abs(T)(T val) { return val >= 0 ? val : -val; } ---
Apr 27 2007
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Frits van Bommel wrote:
 orgoton wrote:
 I've been trying to create a function that would receive a single 
 variable of any type, like a "abs" function, so that I won't have to 
 code the same function for "real" and "long" var types. What's the 
 most straightforward way to do it? I've seen templates at the D 
 documentation, but those require me to instantiate the function. Is 
 there anyway to bypass this?

No, I don't think there's a good way to bypass this. D is a statically typed language, so a function needs to know the types of the arguments. --- // Note: doesn't handle byte.min, short.min, int.min and // long.min correctly because their positive values don't // fit into the corresponding type... :( // (This could be fixed by having abs() return the unsigned // variant of those types, but I don't feel like typing // that much) T abs(T)(T val) { return val >= 0 ? val : -val; } ---

On the other hand, template functions with a single parameter like this are practically guaranteed IFTI (implicit function template instantiation) so he needn't explicitly instantiate it. I think that may be enough for what he seems to be wanting. So given the function above, 'abs(myvar)' will work just fine. I'm also not sure if there's any way to account for the .min issue without writing the function as a member of a normal template and using a chain of static-if's. template abs (T) { static if (is(T == byte )) alias ubyte R; else static if (is(T == short)) alias ushort R; else static if (is(T == int )) alias uint R; else static if (is(T == long )) alias ulong R; else alias T R; R abs (T val) { static if (is(R : ulong)) const ZERO = 0_UL ; else const ZERO = 0.0_L ; return val >= ZERO ? val : -val; } } Just a quick something, I make no claims toward perfection. If he doesn't mind always returning a ulong, I'm sure he could replace all those static-if's with one 'static if(is(T:long))'. -- Chris Nicholson-Sauls
Apr 27 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Chris Nicholson-Sauls wrote:
 Frits van Bommel wrote:
 orgoton wrote:
 [snip] I've seen templates at the D 
 documentation, but those require me to instantiate the function. Is 
 there anyway to bypass this?



 T abs(T)(T val) { return val >= 0 ? val : -val; }

On the other hand, template functions with a single parameter like this are practically guaranteed IFTI (implicit function template instantiation) so he needn't explicitly instantiate it. I think that may be enough for what he seems to be wanting. So given the function above, 'abs(myvar)' will work just fine.

Good point. I didn't consider it was perhaps _explicit_ instantiation he had a problem with, instead of instantiation in general.
 I'm also not sure if there's any way to account for the .min issue 
 without writing the function as a member of a normal template and using 
 a chain of static-if's.
 
 template abs (T) {
        static if (is(T == byte )) alias ubyte  R;
   else static if (is(T == short)) alias ushort R;
   else static if (is(T == int  )) alias uint   R;
   else static if (is(T == long )) alias ulong  R;
   else                            alias T      R;
 
   R abs (T val) {
     static if (is(R : ulong)) const ZERO = 0_UL  ;
     else                      const ZERO = 0.0_L ;
 
     return val >= ZERO ? val : -val;
   }
 }
 
 Just a quick something, I make no claims toward perfection.  If he 

Good, because I'm pretty sure that breaks IFTI. You'd have to implement the static ifs in a separate template for the cleanest working code (I think). Oh, and it seems to assume only primitive types are used (in the body). Any particular reason to use a floating-point zero to compare to? Wouldn't a regular int implicitly convert? And also work for user-defined types implementing opCmp & opNeg?
 doesn't mind always returning a ulong, I'm sure he could replace all 
 those static-if's with one 'static if(is(T:long))'.

That should work for all currently implemented types. It'll still break once cent & ucent are implemented though...
Apr 27 2007
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Frits van Bommel wrote:
 Chris Nicholson-Sauls wrote:
 Frits van Bommel wrote:
 orgoton wrote:
 [snip] I've seen templates at the D documentation, but those require 
 me to instantiate the function. Is there anyway to bypass this?



 T abs(T)(T val) { return val >= 0 ? val : -val; }

On the other hand, template functions with a single parameter like this are practically guaranteed IFTI (implicit function template instantiation) so he needn't explicitly instantiate it. I think that may be enough for what he seems to be wanting. So given the function above, 'abs(myvar)' will work just fine.

Good point. I didn't consider it was perhaps _explicit_ instantiation he had a problem with, instead of instantiation in general.
 I'm also not sure if there's any way to account for the .min issue 
 without writing the function as a member of a normal template and 
 using a chain of static-if's.

 template abs (T) {
        static if (is(T == byte )) alias ubyte  R;
   else static if (is(T == short)) alias ushort R;
   else static if (is(T == int  )) alias uint   R;
   else static if (is(T == long )) alias ulong  R;
   else                            alias T      R;

   R abs (T val) {
     static if (is(R : ulong)) const ZERO = 0_UL  ;
     else                      const ZERO = 0.0_L ;

     return val >= ZERO ? val : -val;
   }
 }

 Just a quick something, I make no claims toward perfection.  If he 

Good, because I'm pretty sure that breaks IFTI. You'd have to implement the static ifs in a separate template for the cleanest working code (I think).

Y'know... I didn't even think of that. Heh. I told you it was quick.
 Oh, and it seems to assume only primitive types are used (in the body). 
 Any particular reason to use a floating-point zero to compare to? 
 Wouldn't a regular int implicitly convert? And also work for 
 user-defined types implementing opCmp & opNeg?

I was just working on the assumption that ints/reals were all he was concerned with. A perfect library-appropriate abs() is another creature.
 doesn't mind always returning a ulong, I'm sure he could replace all 
 those static-if's with one 'static if(is(T:long))'.

That should work for all currently implemented types. It'll still break once cent & ucent are implemented though...

Ah, oy. Sometimes I think we should just "implement" cent/ucent as aliases for long/ulong in the meantime. So many things are going to break when they come to fruition as it is. -- Chris Nicholson-Sauls
Apr 27 2007
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Chris Nicholson-Sauls wrote:
 Frits van Bommel wrote:
 Chris Nicholson-Sauls wrote:
 doesn't mind always returning a ulong, I'm sure he could replace all 
 those static-if's with one 'static if(is(T:long))'.

That should work for all currently implemented types. It'll still break once cent & ucent are implemented though...

Ah, oy. Sometimes I think we should just "implement" cent/ucent as aliases for long/ulong in the meantime. So many things are going to break when they come to fruition as it is.

That might be a bad idea, since the point of fixed-size integers is that they are, you know, fixed-size. :P However, I'd like it if the following compiled: --- import std.stdio; void main() { static if(is(cent)) writefln("cent implemented"); else writefln("no cent yet"); } --- (and gave the correct output, of course) Then anybody who cares about this sort of thing would have a way to test for it. And you could use it to define aliases (max_t & umax_t ?) for the largest signed and unsigned integers.
Apr 28 2007