[racket-dev] What are single flonums good for?

From: Robby Findler (robby at eecs.northwestern.edu)
Date: Sat Sep 15 16:35:13 EDT 2012

Thanks for the explanation. I see how this is not a typed-specific
problem (indeed, it is probably a Good Thing that TR helps us be
careful about this distinction when it matters).

At this point, I'm still left wondering if Single-Flonums are good for
anything, but I can imagine that they are good for not breaking old
programs, so probably best to leave well enough alone.

Thanks again,
Robby

On Sat, Sep 15, 2012 at 9:31 AM, Vincent St-Amour <stamourv at ccs.neu.edu> wrote:
> At Fri, 14 Sep 2012 23:45:43 -0500,
> Robby Findler wrote:
>> The original message in this thread suggests that there is a type
>> Single-Flonum and that it is making Neil wrangle his code to be
>> careful about it.
>
> Right, TR supports `Single-Flonum's, but not `f32vector's.
>
> Part of the complexity in Neil's code is due to types, part of it is not.
>
> Assuming he wrote the math library in untyped Racket:
>
>     (define (foo x)
>        (cond [(double-flonum? x)  (flfoo x)]
>              [(single-flonum? x)  (real->single-flonum
>                                    (flfoo (real->double-flonum x)))]
>              [else  (flfoo (real->double-flonum x))]))
>
> The code is exactly the same as before. The complexity comes from the
> fact that this function, when given single-precision inputs, wants to
> produce single-precision outputs, hence the special case.
>
> If Neil wants `foo' to be as flexible as Racket's built-in operations
> (which, when given single-precision inputs, produce single-precision
> outputs), he needs that special case, types or not.
>
> If he gives up on that flexibility, things become a lot simpler:
>
>     (define (foo x)
>        (flfoo (real->double-flonum x)))
>
> This version still accepts single-precision inputs, but always produces
> doubles.
>
> The types simply mirror that distinction:
>
>     (: foo (case-> (Single-Flonum -> Single-Flonum)
>                     (Flonum -> Flonum)
>                     (Real -> Real)))
>
> vs
>
>     (: foo (Real -> Flonum))
>
> This kind of complexity gets worse for functions with multiple arguments,
> and types make it worse. When expressing coercion rules, the
> implementation can take shortcuts that the type system cannot currently
> express, leading to unwieldy types.
>
> These issues only come up when writing libraries that aim to propagate
> Racket's numeric flexibility, such as the math library or TR's base
> environment. Clients of either don't need to worry about any of that.
>
> Single-precision floats are not the source of this problem (you would
> run into the same issues, in both the untyped and typed worlds, with a
> function that takes ints to ints and floats to floats), but they do add
> one more type to worry about.
>
> Vincent

Posted on the dev mailing list.