www.digitalmars.com         C & C++   DMDScript  

D - type conversions

reply "Pavel Minayev" <evilone omen.ru> writes:
These are a bit weird in D: strings we're already discussing,
now I'd like to point on the others. This time, it's about
int <-> float conversions. I came over this when I was writing
the math module. Suppose the abs function:

    long abs(long n)
    {
        return n > 0 ? n : -n;
    }

    extended abs(extended n)
    {
        // uses inline assembler for FPU's FABS
        asm { ... }
    }

One for integers, one for floats. Now I write:

    x = abs(123);

And get a compiler error! The problem is, 123 is of type int,
and can be converted to both long and extended. So, the
call is ambiguous. This can be solved by writing 123L, thus
explicitly stating that constant is long, but what about
variables?

    int x;
    x = abs(cast(long) x);    // looks weird, no?

Moreover, the same applies to floats:

    x = abs(123.456);

123.456 is double, and can be converted to both long and extended -
ambiguity again, and program fails to compile. You have to:

    x = abs(cast(extended) 123.456);

Of course, one can overload the function for ints and doubles,
but don't forget there are also byte, short, ubyte, ushort,
uint, ulong and float... well, you get the idea. I guess nobody
wants to write all these one-line wrappers just to let
user pass argument of any type to your function - probably,
the compiler should take care of it.

Any ideas?
Apr 05 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a8kumf$vgd$1 digitaldaemon.com...
 Of course, one can overload the function for ints and doubles,
 but don't forget there are also byte, short, ubyte, ushort,
 uint, ulong and float... well, you get the idea. I guess nobody
 wants to write all these one-line wrappers just to let
 user pass argument of any type to your function - probably,
 the compiler should take care of it.

It will be implicitly converted if you have just one function. But when you have multiple functions, and the call doesn't match exactly one, it should return an error. Otherwise, we fall into the C++ quagmire with a long list of such complicated rules about which one is a "better" fit that it just isn't clear what is happening anymore.
Apr 05 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a8lbqc$1d7s$2 digitaldaemon.com...

 It will be implicitly converted if you have just one function. But when

 have multiple functions, and the call doesn't match exactly one, it should
 return an error. Otherwise, we fall into the C++ quagmire with a long list
 of such complicated rules about which one is a "better" fit that it just
 isn't clear what is happening anymore.

It doesn't seem that it would be better. Some set of rules is still needed, IMO. Something like this: - any int can be casted to any other int (bit is an int), difficulty 1 - any float can be casted to any other float, difficulty 1 - any int can be casted to any float, difficulty 2 - any float can be casted to any int, difficulty 2 Compiler tries to minimize conversion difficulty when resolving ambiguity. So, whenever you pass an int literal, it will _first_ look for functions taking long, short, byte etc. Only then it tries floats. This means you could supply just two versions of every function: long foo(long) { ... } extended foo(extended) { ... } Now, any int type will be converted to foo, since it's "easier" than converting to extended, and every float will be converted to extended, since it's easier than converting to long.
Apr 05 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a8lrq4$25k7$2 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:a8lbqc$1d7s$2 digitaldaemon.com...
 It will be implicitly converted if you have just one function. But when

 have multiple functions, and the call doesn't match exactly one, it


 return an error. Otherwise, we fall into the C++ quagmire with a long


 of such complicated rules about which one is a "better" fit that it just
 isn't clear what is happening anymore.

needed, IMO. Something like this:

I understand what you mean and the motivation behind it. They're good reasons. But I want to try the three level system of one match, exact match, or ambiguous.
Apr 05 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a8m5hc$2icj$1 digitaldaemon.com...

 I understand what you mean and the motivation behind it. They're good
 reasons. But I want to try the three level system of one match, exact

 or ambiguous.

Then, for your system, which is the correct way to define a function which has two distinct versions for floats and ints, and is able to take arguments of any appropriate type: float, double, extended for float version, and byte, ubyte, short, ushort, int, uint, long, ulong for int version? Do you suggest to write wrappers for every possible case?
Apr 06 2002
next sibling parent reply "OddesE" <OddesE_XYZ hotmail.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a8mkdf$na9$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:a8m5hc$2icj$1 digitaldaemon.com...

 I understand what you mean and the motivation behind it. They're good
 reasons. But I want to try the three level system of one match, exact

 or ambiguous.

Then, for your system, which is the correct way to define a function which has two distinct versions for floats and ints, and is able to take arguments of any appropriate type: float, double, extended for float version, and byte, ubyte, short, ushort, int, uint, long, ulong for int version? Do you suggest to write wrappers for every possible case?

Why isn't there a distinction between integral types and floating point types that is stronger than just typea != typeb? byte, short, int, long etc are all integral types, float, double and extended are floating point types. How about this: integral abs(integral n) { return n > 0 ? n : -n; } floating abs(floating n) { // uses inline assembler for FPU's FABS asm { ... } } Where the compiler will interpret any argument that fits a category as an exact match. Implementation of the function will always take the largest size available on the platform for that type category, making all smaller sizes 'fit'. This might also work for char and wchar: character upcase (character c) { // ... } Where character is the category into which all char-types fall, 8, 16 or 32 bit's. Just an idea... :) -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net _________________________________________________ Remove _XYZ from my address when replying by mail
Apr 06 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"OddesE" <OddesE_XYZ hotmail.com> wrote in message
news:a8n4jq$19iu$1 digitaldaemon.com...

 How about this:

 Where the compiler will interpret any
 argument that fits a category as an exact match.
 Implementation of the function will always
 take the largest size available on the platform
 for that type category, making all smaller
 sizes 'fit'.

Isn't it simplier to just use "long" and "extended" (since they are always the largest, on any platform)?
Apr 06 2002
parent reply "OddesE" <OddesE_XYZ hotmail.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a8n8c3$1db8$1 digitaldaemon.com...
 "OddesE" <OddesE_XYZ hotmail.com> wrote in message
 news:a8n4jq$19iu$1 digitaldaemon.com...

 How about this:

 Where the compiler will interpret any
 argument that fits a category as an exact match.
 Implementation of the function will always
 take the largest size available on the platform
 for that type category, making all smaller
 sizes 'fit'.

Isn't it simplier to just use "long" and "extended" (since they are always the largest, on any platform)?

But then you keep the problem that it isn't an exact match. With type categories the programmer could explicitly state that he allows all types in the category to be used and that he expects that behaviour. Any integer type would always be a valid 'exact match' with any integral argument. Only if there where a function that was an exact match based on type instead of type category, that function would be called instead. -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net _________________________________________________ Remove _XYZ from my address when replying by mail
Apr 07 2002
parent "Matthew Wilson" <mwilson nextgengaming.com> writes:
I kind of like this idea, but isn't it very much like templates & traits.

If Walter would be interested in incorporating a (designed from the ground
up, hence) better template implementation than has C++ (resulting in all the
arcane wangles we have to do to get traits to manipulate type categories,
etc.), then I think the appeal of D would widen very quickly (not that it
isn't appealing already ... ;)

"OddesE" <OddesE_XYZ hotmail.com> wrote in message
news:a8p5km$12d5$1 digitaldaemon.com...
 "Pavel Minayev" <evilone omen.ru> wrote in message
 news:a8n8c3$1db8$1 digitaldaemon.com...
 "OddesE" <OddesE_XYZ hotmail.com> wrote in message
 news:a8n4jq$19iu$1 digitaldaemon.com...

 How about this:

 Where the compiler will interpret any
 argument that fits a category as an exact match.
 Implementation of the function will always
 take the largest size available on the platform
 for that type category, making all smaller
 sizes 'fit'.

Isn't it simplier to just use "long" and "extended" (since they are always the largest, on any platform)?

But then you keep the problem that it isn't an exact match. With type categories the programmer could explicitly state that he allows all types in the category to be used and that he expects that behaviour. Any integer type would always be a valid 'exact match' with any integral argument. Only if there where a function that was an exact match based on type instead of type category, that function would be called instead. -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net _________________________________________________ Remove _XYZ from my address when replying by mail

May 06 2002
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a8mkdf$na9$1 digitaldaemon.com...
 Then, for your system, which is the correct way to define a function
 which has two distinct versions for floats and ints, and is able to
 take arguments of any appropriate type: float, double, extended for
 float version, and byte, ubyte, short, ushort, int, uint, long, ulong
 for int version? Do you suggest to write wrappers for every possible
 case?

For the abs() case, I'd just do abs(long) for integral types, and fabs(extended) for floating point types.
Apr 06 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a8naiu$1fr8$1 digitaldaemon.com...

 For the abs() case, I'd just do abs(long) for integral types, and
 fabs(extended) for floating point types.

So: min and fmin max and fmax avg and favg ... Then what's the point of function overloading? Seems we're back to C times...
Apr 06 2002
next sibling parent "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a8njrd$1qjh$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:a8naiu$1fr8$1 digitaldaemon.com...
 For the abs() case, I'd just do abs(long) for integral types, and
 fabs(extended) for floating point types.

min and fmin max and fmax avg and favg ... Then what's the point of function overloading? Seems we're back to C times...

I'm of the curmudgeonly opinion that function overloading should be used sparingly and that if used, then the argument types should match exactly. I've spent too many hours trying to get the "best" match idea working right in C++. I've run into too much code that was hard to figure out which function was getting called due to subtleties of the "best" match algorithm. It's not worth it. With abs() and fabs(), you only have two functions to handle all the arithmetic types. It's not so bad <g>.
Apr 06 2002
prev sibling parent reply "Stephen Fuld" <s.fuld.pleaseremove att.net> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a8njrd$1qjh$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
 news:a8naiu$1fr8$1 digitaldaemon.com...

 For the abs() case, I'd just do abs(long) for integral types, and
 fabs(extended) for floating point types.

So: min and fmin max and fmax avg and favg ...

Worse than that, since you can compare characters for greater than, etc. it seems reasonable to allow max and min on them as well. Now you have three types to declare for those. -- - Stephen Fuld e-mail address disguised to prevent spam
Apr 06 2002
parent "Pavel Minayev" <evilone omen.ru> writes:
"Stephen Fuld" <s.fuld.pleaseremove att.net> wrote in message
news:a8pt6h$2g47$1 digitaldaemon.com...

 Worse than that, since you can compare characters for greater than, etc.

 seems reasonable to allow max and min on them as well.  Now you have three
 types to declare for those.

If I recall it correctly, characters are castable to ints, so the integer version would be used by the compiler.
Apr 07 2002