Code Monkey home page Code Monkey logo

Comments (5)

polytypic avatar polytypic commented on June 3, 2024

It is the wonders of overloading. The job builder has two overloads for For and apparently the array overload gets selected by default. Can you give a type for the xs parameter?

from hopac.

davidgrenier avatar davidgrenier commented on June 3, 2024

Hmmm, it clearly wouldn't have been sound to give overloading precedence based on the order it was defined in the builder but sure would've been convenient.

I've been trying to define a combined builder for Validation+Reader in the hope of supporting:

'context -> 'a
'context -> Choice<'a, 'b>
Choice<'a, 'b>

Naturally I could only support both 'context -> Choice<'a, 'b> and Choice<'a, 'b>

from hopac.

t0yv0 avatar t0yv0 commented on June 3, 2024

Could also try quasi-static overloading:

let length<'E,'T when 'T :> seq<'E>> : 'T -> int =
   if typeof<'T>.IsArray then
       Array.length<'E> :> obj :?> _
   else
       fun xs -> Seq.length xs

Code along these lines can be arranged that selection happens O(1) at application startup.

from hopac.

polytypic avatar polytypic commented on June 3, 2024

This is a surprisingly complex issue. Normally I would think that this is not a
very critical issue in any way. But... I think that issues like this arise from
mixing subtyping and overloading occasionally, so I've spent some time looking
at the "Method Application Resolution" rules of F# to see if there would be way
to guide the resolution process usefully.

Unfortunately, I don't see how to do that in this case. This is not to say that
it would be impossible. I considered adding optional arguments to "poison"
overloads, but that effectively eliminates those overloads completely. I also
considered using extension methods. There is a special rule that the most
recently opened extension methods are preferred, but unfortunately that doesn't
seem to apply in this case. I don't immediately see other rules that might help
in this caseโ€”at least not without substantial trickery, which I'd prefer
to avoid.

If I understand the overload resolution specification correctly, the reason F#
chooses the array overload is that it has a more specific type than the seq
overload. This is basically sound.

If we'd add another overload, say for lists, which is actually something I've
had in mind, but have not yet implemented, the resolution process would fail and
report an error for the example code. To fix the code to compile, one could
simply add the type constraint (xs: seq<_>). Because adding such overloads is
something I've already considered doing, but haven't yet had the time, and
because this would merely have the effect of requiring user code to be more
explicit about types and would not impede compiler optimizations like inlining,
I find this to be a reasonable solution.

The suggested quasi static approach can be quite nice in certain contexts. I've
used similar techniques in cases where I've effectively wanted a mapping from
types to values.

The quasi static approach has the following properties:

  • The JIT will generate a bit of static data for every type that the quasi
    static thing is used with. In this case for every type
    CollectionType<ElementType>.
  • With initializer code, the JIT will also generate a bit of code at every
    access to the quasi static data to check whether the initialization code has
    already been run or not and to run the initialization code if not. Without
    initializer code, in this case, we would need to write an equivalent
    initialization check, because the default uninitialized value will not help.
  • In this case we also need to invoke functionality via that static data, so
    there is a need to perform a virtual method call. Aside from the cost of the
    virtual call itself, this will have the effect of preventing F# from
    performing inlining.

In this particular case inlining is not used, but since For is given a closure
as an argument, there is a possibility that inlining performed by F# could give
significant benefits. In this case we also don't necessarily want a full
mapping from all CollectionType<ElementType> types to a specialized for loop.
We only want to choose between two (or few) generic specilizations for different
collections.

If we ignore the potential for inlining and many more specialized versions of
For would be added, then the quasi static approach would likely become faster
than a run-time type test, but for choosing between seq and array
specialization, a run-time type test (i.e. having just a single seq version of
For that checks if the given sequence is an array) is likely to be faster (type
tests seem to have a cost similar to the cost a virtual function call).

I don't really like either way of specializing the behavior of For in this case
(run time tests or the quasi static method).

For best performance, I'd choose the option of adding another overload, which
will require used code to be explicit about the types.

The simplest thing to do would be to simply remove the array overload. This
would require user code to very explicitly use array specific code when desired
as an optimization.

So, I'm basically leaning towards either removing the array overload or adding a
list overload. Both approaches require user code to be more specific, but in
different ways.

from hopac.

t0yv0 avatar t0yv0 commented on June 3, 2024

Indeed. The simplest thing that works, is drop this overload and do:

Job.forArray arr (fun item -> job { .. })

from hopac.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.