Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add struct-based versions of library functions #771

Open
Tarmil opened this issue Jul 16, 2019 · 1 comment

Comments

@Tarmil
Copy link

commented Jul 16, 2019

Add struct-based versions of library functions

I propose we add dedicated modules that contain functions identical to existing standard library function except that they work on struct tuples and voptions rather than ref tuples and options. There are currently about a hundred such functions.

The best solution IMO would be new namespaces FSharp.Collections.Struct and FSharp.Control.Struct. This would give us the following new functions:

    FSharp.Collections.Struct.Array.allPairs
    FSharp.Collections.Struct.Array.choose
    FSharp.Collections.Struct.Array.countBy
    FSharp.Collections.Struct.Array.groupBy
    FSharp.Collections.Struct.Array.indexed
    FSharp.Collections.Struct.Array.mapFold
    FSharp.Collections.Struct.Array.mapFoldBack
    FSharp.Collections.Struct.Array.pairwise
    FSharp.Collections.Struct.Array.partition
    FSharp.Collections.Struct.Array.pick
    FSharp.Collections.Struct.Array.splitAt
    FSharp.Collections.Struct.Array.tryExactlyOne
    FSharp.Collections.Struct.Array.tryFind
    FSharp.Collections.Struct.Array.tryFindBack
    FSharp.Collections.Struct.Array.tryFindIndex
    FSharp.Collections.Struct.Array.tryFindIndexBack
    FSharp.Collections.Struct.Array.tryHead
    FSharp.Collections.Struct.Array.tryItem
    FSharp.Collections.Struct.Array.tryLast
    FSharp.Collections.Struct.Array.tryPick
    FSharp.Collections.Struct.Array.unfold
    FSharp.Collections.Struct.Array.unzip
    FSharp.Collections.Struct.Array.unzip3
    FSharp.Collections.Struct.Array.zip
    FSharp.Collections.Struct.Array.zip3

    FSharp.Collections.Struct.List.allPairs
    FSharp.Collections.Struct.List.choose
    FSharp.Collections.Struct.List.countBy
    FSharp.Collections.Struct.List.groupBy
    FSharp.Collections.Struct.List.indexed
    FSharp.Collections.Struct.List.mapFold
    FSharp.Collections.Struct.List.mapFoldBack
    FSharp.Collections.Struct.List.pairwise
    FSharp.Collections.Struct.List.partition
    FSharp.Collections.Struct.List.pick
    FSharp.Collections.Struct.List.splitAt
    FSharp.Collections.Struct.List.tryExactlyOne
    FSharp.Collections.Struct.List.tryFind
    FSharp.Collections.Struct.List.tryFindBack
    FSharp.Collections.Struct.List.tryFindIndex
    FSharp.Collections.Struct.List.tryFindIndexBack
    FSharp.Collections.Struct.List.tryHead
    FSharp.Collections.Struct.List.tryItem
    FSharp.Collections.Struct.List.tryLast
    FSharp.Collections.Struct.List.tryPick
    FSharp.Collections.Struct.List.unfold
    FSharp.Collections.Struct.List.unzip
    FSharp.Collections.Struct.List.unzip3
    FSharp.Collections.Struct.List.zip
    FSharp.Collections.Struct.List.zip3

    FSharp.Collections.Struct.Seq.allPairs
    FSharp.Collections.Struct.Seq.choose
    FSharp.Collections.Struct.Seq.countBy
    FSharp.Collections.Struct.Seq.groupBy
    FSharp.Collections.Struct.Seq.indexed
    FSharp.Collections.Struct.Seq.mapFold
    FSharp.Collections.Struct.Seq.mapFoldBack
    FSharp.Collections.Struct.Seq.pairwise
    FSharp.Collections.Struct.Seq.pick
    FSharp.Collections.Struct.Seq.tryExactlyOne
    FSharp.Collections.Struct.Seq.tryFind
    FSharp.Collections.Struct.Seq.tryFindBack
    FSharp.Collections.Struct.Seq.tryFindIndex
    FSharp.Collections.Struct.Seq.tryFindIndexBack
    FSharp.Collections.Struct.Seq.tryHead
    FSharp.Collections.Struct.Seq.tryItem
    FSharp.Collections.Struct.Seq.tryLast
    FSharp.Collections.Struct.Seq.tryPick
    FSharp.Collections.Struct.Seq.unfold
    FSharp.Collections.Struct.Seq.zip
    FSharp.Collections.Struct.Seq.zip3

    FSharp.Collections.Struct.Map.ofArray
    FSharp.Collections.Struct.Map.ofList
    FSharp.Collections.Struct.Map.ofSeq
    FSharp.Collections.Struct.Map.partition
    FSharp.Collections.Struct.Map.pick
    FSharp.Collections.Struct.Map.toArray
    FSharp.Collections.Struct.Map.toList
    FSharp.Collections.Struct.Map.toSeq
    FSharp.Collections.Struct.Map.tryFind
    FSharp.Collections.Struct.Map.tryFindKey
    FSharp.Collections.Struct.Map.tryPick

    FSharp.Collections.Struct.Set.partition

    FSharp.Control.Struct.Event.choose
    FSharp.Control.Struct.Event.pairwise
    FSharp.Control.Struct.Event.partition
    FSharp.Control.Struct.Event.split // this should probably wait until we have ValueChoice

    FSharp.Control.Struct.Observable.choose
    FSharp.Control.Struct.Observable.pairwise
    FSharp.Control.Struct.Observable.partition
    FSharp.Control.Struct.Observable.split // this should probably wait until we have ValueChoice

    FSharp.Control.Struct.Async.AsBeginEnd
    FSharp.Control.Struct.Async.Choice
    FSharp.Control.Struct.Async.FromContinuations

Doing this instead of adding new functions or submodules inside existing modules (eg List.Struct.tryFind or List.structTryFind) would allow different levels of buy-in:

  • Existing code would work as usual with ref types.

  • A user who wants to automatically use structs everywhere can write:

    open FSharp.Collections.Struct
    open FSharp.Control.Struct
  • A user who wants to automatically use the struct version of specific modules can write:

    module List = FSharp.Collections.Struct.List
    module Event = FSharp.Control.Struct.Event
  • A user who wants to explicitly use the struct version of a function can write:

    let x = Struct.List.tryFind f l
    let e' = Struct.Event.pairwise e

Pros and Cons

The advantages of making this adjustment to F# are:

  • Allow reduced memory allocations when using standard library functions for users who explicitly care about it.

The disadvantages of making this adjustment to F# are:

  • A lot of new functions added to stdlib, which means more code to test, bigger FSharp.Core.dll, etc. Although a number of them should be able to share most of the existing implementation.

Extra information

Estimated cost (XS, S, M, L, XL, XXL): L

Related suggestions: (put links to related suggestions here)

Affidavit (please submit!)

Please tick this by placing a cross in the box:

  • This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
  • I have searched both open and closed suggestions on this site and believe this is not a duplicate
  • This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:

  • This is not a breaking change to the F# language design
  • I or my company would be willing to help implement and/or test this
@cmeeren

This comment has been minimized.

Copy link

commented Jul 22, 2019

Note that this overlaps with #739 and linked issue/PR.

Also, personally I'm not sure if I like the idea of identical names in a different namespace. At least IMHO it should be e.g. List.Struct.pick and not the other way around.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.