Re: implementation specific vs. standardized Dr. Arne Babenhauserheide 18 Sep 2026 06:56 UTC
Hi Artyom,

Artyom Bologov <xxxxxx@aartaka.me> writes:

> Oh, that might be one of the draft 2 revisions I made, sorry.

I didn’t doublecheck, I might have just overlooked it.

But I think it’s good, so no need to be sorry :-)

>> But an argument for a specific procedure could be narrower. The
>> procedure might even have multiple pre-compiled instances of itself to
>> which it dispatches depending on the type of the argument, so asking
>> procedure-type-of could be a way to discover which check predicate could
>> enforce efficient use of the procedure.
>
> Hmmmm, that’s problematic. But I am hesitant to go down the road of
> accomodating this—too many implementation-specific behaviors emerge if
> we abandon the “atomicity” of procedures.

The reason I see that is that Javascript does it (excessively). It’s one
reason why it got so fast (and memory-hungry), even though you can throw
its functions anything and then they do something.
Here’s a description of the method:
https://dl.acm.org/doi/full/10.1145/3798245#sec-2-2

>> Example: procedure-type-of returns that the procedure can take values
>> that match (and (real? x) (inexact? x))
>> That’s basically floating point.
>> By now adding (lambda (x) (and (real? x) (inexact? x))) as check for the
>> procedure, you could enforce that it is only used with arguments that
>> enable optimized operation.
>>
>> For this is could be useful to provide a list of possible types, from
>> the narrowest to the broadest. Basically ask the compiler what types it
>> can optimize for.
>
> Not sure I understood this point. So what you’re saying is that types
> come in hierarchies and thus procedure-type-of has to return a list of
> these for more granular operation? And a list of possible “methods” in
> general?

Not multiple methods (because they aren’t accessible individually), but
if it asks which type the procedure uses, the answer could actually be
several different ones.

For example in my benchmark the magnitude procedure with typed arguments
is factor 3 faster than the untyped one, because its inner functions are
specialized to floats.

;; untyped
(define (magnitude/untyped x y)
  (sqrt (+ (* x x) (* y y))))

;; typed
(define-inlinable (float? x)
  (and (real? x) (inexact? x)))
(define-typed (magnitude/typed x y) (float? float?)
  (sqrt (+ (* x x) (* y y))))

If I could ask sqrt, +, and * which types they accept, I could find the
most specific type and use it as checked type for the magnitude/typed
procedure.

Then the compiler can optimize out the type checks and dispatch of the
inner procedure calls.

That would be a convenient, portable way to find some of the
optimizations David Thompson shows in
https://dthompson.us/posts/optimizing-guile-scheme.html

But I don’t know how hard it would be for implementations to provide
this (if it’s too hard, it could block them from adopting this SRFI,
voiding the advantage).

> • Disassemblers and optimizers. Checks don’t really have the granularity
>   needed for e.g. proper optimization.
> • Introspection. Checks are too unstructured, being plain
>   procedures. While types / classes might be objects with their own
>   structure. Going beyond the hierarchy which you suggest to
>   special-case here.
>
> Uses for this SRFI in general:
>
> • In-editor suggestions you mentioned
> • REPL introspection, quick type lookup
> • Auto-generated documentation systems. Like scheme-index, but, like,
>   auto-generated
>
> There are more, probably, but I only care about introspection in the
> abstract and cannot anticipate all the uses others might find for this
> SRFI.

The core question for me is here: what do people need as portable
procedure? Is type-of intended to trigger an implementation specific
output or is it intended to be a building block for portable tools?

Best wishes,
Arne
--
Unpolitisch sein
heißt politisch sein,
ohne es zu merken.
https://www.draketo.de