Jump to page: 1 2
Thread overview
type conversions
Apr 05, 2002
Pavel Minayev
Apr 05, 2002
Walter
Apr 06, 2002
Pavel Minayev
Apr 06, 2002
Walter
Apr 06, 2002
Pavel Minayev
Apr 06, 2002
OddesE
Apr 06, 2002
Pavel Minayev
Apr 07, 2002
OddesE
May 07, 2002
Matthew Wilson
Apr 06, 2002
Walter
Apr 06, 2002
Pavel Minayev
Apr 07, 2002
Walter
Apr 07, 2002
Stephen Fuld
Apr 07, 2002
Pavel Minayev
April 05, 2002
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?


April 05, 2002
"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.


April 06, 2002
"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
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.

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.


April 06, 2002
"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
> 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.
> It doesn't seem that it would be better. Some set of rules is still 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.


April 06, 2002
"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
match,
> 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?


April 06, 2002
"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
> match,
> > 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



April 06, 2002
"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)?




April 06, 2002
"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.


April 06, 2002
"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...


April 07, 2002
"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
>     ...
> 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>.


« First   ‹ Prev
1 2