Thread overview
float -> double conversion
May 04, 2002
Walter
May 04, 2002
Jonathan Andrew
May 04, 2002
Pavel Minayev
May 04, 2002
Burton Radons
May 04, 2002
Burton Radons
May 04, 2002
In C, floats passed as a variant function argument get promoted to doubles. This is an artifact of how the PDP-11 floating point hardware worked, and has become thoroughly ingrained into C ever since. Should D break this? The advantage is that it saves a bit of space and time. The options are:

1) Just leave it the C way.
2) Pass them as floats - this will require a new float format for printf.


May 04, 2002
Walter wrote:

> In C, floats passed as a variant function argument get promoted to doubles.
> This is an artifact of how the PDP-11 floating point hardware worked, and
> has become thoroughly ingrained into C ever since. Should D break this? The
> advantage is that it saves a bit of space and time. The options are:
> 
> 1) Just leave it the C way.
> 2) Pass them as floats - this will require a new float format for printf.
> 
> 
> 

Yes! Break it, I think leaving it as-is breaks the philosophy of
"arbitrary, obscure, and forgettable rules in ambiguous cases" ;)

-Jon

May 04, 2002
"Jonathan Andrew" <jon@ece.arizona.edu> wrote in message news:3CD34661.3000304@ece.arizona.edu...

> Yes! Break it, I think leaving it as-is breaks the philosophy of "arbitrary, obscure, and forgettable rules in ambiguous cases" ;)

What about short->int then? It should be forbidden as well... but why? I mean, it doesn't hurt after all, no data loss occurs, and you don't have to remember all the specifiers. ints are %d. floats are %f.

By the way, there is another idea. Convert byte, short, int -> long, and float, double -> extended. After doing that, there is no longer need in %Ld and %Lf.


May 04, 2002
On Fri, 3 May 2002 17:13:09 -0700, "Walter" <walter@digitalmars.com> wrote:

>In C, floats passed as a variant function argument get promoted to doubles. This is an artifact of how the PDP-11 floating point hardware worked, and has become thoroughly ingrained into C ever since. Should D break this? The advantage is that it saves a bit of space and time. The options are:
>
>1) Just leave it the C way.
>2) Pass them as floats - this will require a new float format for printf.

C varargs should be as simple to parse as possible; they're already unwieldy enough as it is, and printf formatting emphatically does not need extra complications.  Particularly to save a couple bytes on functions that are only rarely recursed.

I think the opposite route should be taken: varargs should be refined so that they have an associated object that allows the caller to abstractly retrieve arguments.  For example, with something like:

    wchar[] fmt(wchar[] format, args...);

Where args is an instance of:

    class Varargs
    {
        int length (); /* Number of arguments */
        Type type (int index); /* Get the runtime type of an argument
*/
        bit get (int index, out $type value); /* Try to get a single
value, converting if possible */

        /* Without generics... */
        bit get_int (int index, out int value);
        ...
    }

Then min could be generically written as:

    $type min ($type a, args...)
    {
        $type n;
        int c;

        for (c = 0; c < args.length; c ++)
        {
            if (!args.get (c, n))
                throw new Error ("incompatible types in min");
            if (n < a)
                a = n;
        }

        return a;
    }

Although it would of course be better to have a couple specific argument counts first in lieu of a very intelligent compiler.

Take the code I use to get extended from the C varargs stream:

    value = *(extended*) args;
    args += (extended.size + 3) & ~3;

Beautiful, no?  With a varargs object I could just ask for an extended from the stream and get it (if possible), no problems.  It could even be a float as passed, or an int, or a byte, but I'll still get my extended.  We wouldn't even need "%lg" any more (or the 'l' flag at all) or think through complex; just always use complex internally, always use wchar, always use long/ulong, with a clean handling of cent/ucent later.
May 04, 2002
On Sat, 04 May 2002 03:09:06 -0700, Burton Radons <loth@users.sourceforge.net> wrote:

[snip]
>I think the opposite route should be taken: varargs should be refined so that they have an associated object that allows the caller to abstractly retrieve arguments.  For example, with something like:
>
>    wchar[] fmt(wchar[] format, args...);
>
>Where args is an instance of:
>
>    class Varargs
>    {
>        int length (); /* Number of arguments */
>        Type type (int index); /* Get the runtime type of an argument
>*/
>        bit get (int index, out $type value); /* Try to get a single
>value, converting if possible */
> 
>        /* Without generics... */
>        bit get_int (int index, out int value);
>        ...
>    }
[snip]

To further extend this issue, varargs are just a part of the argument construction and destruction that you have to do for automated script interfacing.  Let's say that we made it generic; "class Arguments" instead of Varargs.  This is immutable in this case but a subclass, "class ArgumentsBuilder : Arguments" would be mutable and take a "void add ($type value);" method, among others.  The constructor for that would also take the calling convention as an argument.

Say that you want to call a D function from Python.  First you export it:

    void qbert (int a, float b);

    ...
    PyExport (qbert.type);

Then to call it you start building the arguments:

    PyObject *tuple = from function call;
    ArgumentsBuilder args;
    FunctionInfo func = retrieved from our proxy function object;
    int intValue;
    int c;

    /* Function overloading could be handled with some effort... */
    if (func.args.length != PyTuple_Size (tuple))
        /* Error */

    args = new DArgumentsBuilder (func.convention);
    for (c = 0; c < func.args.length; c ++)
    {
        FunctionArgumentInfo arg = func.args [c];
        PyObject *tuple_arg;

        /* Check argument parameters, bail if dimensions are weird */
        tuple_arg = PyTuple_GET_ITEM (tuple, c);
        switch (arg.basetype)
        {
            case BaseType.Int:
                intValue = PyInt_AsLong (tuple_arg);
                if (PyErr_Occurred ())
                    /* Error, not convertable */
                args.add ((int) intValue);
                break;
            /* ... */
        }
    }

    /* Check return parameters and dimensions */
    switch (func.returnType.basetype)
    {
        case BaseType.Int:
        case BaseType.Long:
            args.call (func.pointer, intValue);
            return PyInt_FromLong (intValue);
    }

It's still a lot of code to support it properly, but it offloads all the nonportable concerns and is a hell of a lot simpler than asm code I've seen for dispatch (which this may degenerate into internally... none of my beeswax), and it could support a great variety of operations automatically.

This could be made even easier by taking a subclass of ArgumentsBuilder that instead takes a FunctionInfo as a construction argument, and automatically casts as you add arguments to it.  This would greatly lessen the number of cases above as Python only has two integer types.

The object ownership issue is another thing entirely.  I suspect you would have to construct proxy structs that reference our objects, and are thus included in the GC and also in Python.  It's tricky stuff.

To support the other direction, calling Python from D, you would have to be able to get the "Arguments" instance of the current function. Failing that you could just do:

    /* Takes int, float, char[] */
    int python_function_to_call (args...)
    {
        int value;

        PyDispatch ("python_function_to_call", args, value);
        return value;
    }

Things get more complicated when you try to subclass D classes in Python.  Calling D superclass methods is not a problem, but getting D to call Python automatically.  I can't think through any easy solution right now.