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

Provide universal tuple item accessor functions in FSharp.Core #628

Open
0x53A opened this Issue Nov 28, 2017 · 5 comments

Comments

Projects
None yet
4 participants
@0x53A
Contributor

0x53A commented Nov 28, 2017

(ref Microsoft/visualfsharp#4034)

Provide universal tuple item accessor functions in FSharp.Core

As it currently stands, fst and snd only work with tuples of size 2.
I propose to extend these two to work with all tuple-like objects of different sizes and to add additional accessor functions (proposed naming scheme: itemX) up to some arbitrary limit (proposed: up to item20).

Tuple-like objects in this context includes System.Tuple, System.ValueTuple and everything that exposes ItemX / Rest.

Usage

let tpl = (1,2,3,4)
let x = fst tpl

let tpl = struct (1,2,3,4,5)
let x = fst tpl

Implementation

Microsoft/visualfsharp#4034 exposes ItemX and Rest on System.Tuple with a warning and hidden from intellisense.

The same would need to be done for System.ValueTuple.

Then the acessor functions can be implemented using SRTP.

The existing way of approaching this problem in F# is ...

  • manually destructuring it
  • lots of cursing

Pros and Cons

The advantages of making this adjustment to F# are ...

  • it unifies System.Tuple, System.ValueTuple (exposing ItemX / Rest only for System.Tuple, not for the struct version adds some potential confusion and that should IMO be done regardless of adding these accessor functions)
  • all tuple-like objects (System.Tuple, System.ValueTuple, and everything that exposes ItemX) can be handled the same way.
  • the already existing fst and snd become actually usefull.
  • getting single items from a large tuple is kinda annoying and error prone:
// current way
let (_,_,_,x,_,_,_) = (1,2,3,4,5,6,7)
// new way
let x = item4 (1,2,3,4,5,6,7)
    • you always need to ignore all other items except the one you want
    • you need to count the number of ignored items to see which one you get

The disadvantages of making this adjustment to F# are ...

  • using records is generally preferred over using large tuples
  • by destructuring, you are forced to give the items names. Using ItemX or these accessor functions may make code less readable.

To explicitly respond to

People are lazy and love hitting . ....making Item properties available in intellisense lists will not remotely increase the quality of F# code being written, and indeed will harm it.

The small advantage of these accessor functions over ItemX / Rest properties is that they are not directly visible in IntelliSense. So if you just hit the dot on a tuple, you still don't see them.

Extra information

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

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
@dsyme

This comment has been minimized.

Show comment
Hide comment
@dsyme

dsyme Dec 1, 2017

Collaborator

Some cons are discussed here: Microsoft/visualfsharp#3729 (comment)

Collaborator

dsyme commented Dec 1, 2017

Some cons are discussed here: Microsoft/visualfsharp#3729 (comment)

@dsyme dsyme added the probably not label Dec 1, 2017

@0x53A 0x53A changed the title from Expose ItemX, Rest on tuples and provide universal accessor functions in the corlib to Provide universal tuple item accessor functions in FSharp.Core Dec 5, 2017

@0x53A

This comment has been minimized.

Show comment
Hide comment
@0x53A

0x53A Dec 5, 2017

Contributor

Op edited to clarify that this is mostly about accessor functions. The properties would still produce a warning and be hidden from intellisense.

Contributor

0x53A commented Dec 5, 2017

Op edited to clarify that this is mostly about accessor functions. The properties would still produce a warning and be hidden from intellisense.

@drvink

This comment has been minimized.

Show comment
Hide comment
@drvink

drvink Jan 12, 2018

Who says you can't already use SRTP? The king returns! ;) Here's a new one for @gusty to appreciate:

#light "off"
#nowarn "62";;

#r "System.ValueTuple.dll";;

type fstsnd = class
  static member Fst (struct (x, _)) = x
  static member Fst ((x, _)) = x
  static member Snd (struct (_, y)) = y
  static member Snd ((_, y)) = y

  static member inline _invoke_fst (x : ^a) =
    let inline call (arg, _ : ^b) =
      ((^a or ^b) : (static member Fst : _ -> _) arg) in
    call (x, Unchecked.defaultof<fstsnd>)

  static member inline _invoke_snd (x : ^a) =
    let inline call (arg, _ : ^b) =
      ((^a or ^b) : (static member Snd : _ -> _) arg) in
    call (x, Unchecked.defaultof<fstsnd>)
end

let inline xfst x = fstsnd._invoke_fst x
let inline xsnd x = fstsnd._invoke_snd x

let x = xfst (struct (1, 2))
let y = xfst (3, 4)
let xx = xsnd (struct (5, 6))
let yy = xsnd (7, 8)

drvink commented Jan 12, 2018

Who says you can't already use SRTP? The king returns! ;) Here's a new one for @gusty to appreciate:

#light "off"
#nowarn "62";;

#r "System.ValueTuple.dll";;

type fstsnd = class
  static member Fst (struct (x, _)) = x
  static member Fst ((x, _)) = x
  static member Snd (struct (_, y)) = y
  static member Snd ((_, y)) = y

  static member inline _invoke_fst (x : ^a) =
    let inline call (arg, _ : ^b) =
      ((^a or ^b) : (static member Fst : _ -> _) arg) in
    call (x, Unchecked.defaultof<fstsnd>)

  static member inline _invoke_snd (x : ^a) =
    let inline call (arg, _ : ^b) =
      ((^a or ^b) : (static member Snd : _ -> _) arg) in
    call (x, Unchecked.defaultof<fstsnd>)
end

let inline xfst x = fstsnd._invoke_fst x
let inline xsnd x = fstsnd._invoke_snd x

let x = xfst (struct (1, 2))
let y = xfst (3, 4)
let xx = xsnd (struct (5, 6))
let yy = xsnd (7, 8)
@0x53A

This comment has been minimized.

Show comment
Hide comment
@0x53A

0x53A Jan 12, 2018

Contributor

based on @drvink 's genious I extended it for tuples of size 2 - 9: https://gist.github.com/0x53A/61b10a21c2524580999ccce9cec52c2b

Contributor

0x53A commented Jan 12, 2018

based on @drvink 's genious I extended it for tuples of size 2 - 9: https://gist.github.com/0x53A/61b10a21c2524580999ccce9cec52c2b

@gusty

This comment has been minimized.

Show comment
Hide comment
@gusty

gusty Jan 12, 2018

Guys, you're right, SRTP solve it, though for a limited number of elements.

I have wrote some stuff like that for F#+ but mainly to get lenses for tuples. I agree with @dsyme in that accessing the tuples by properties (or even by fst and snd) is not generally a good idea. But sometimes when writing generic code you need to do stuff like that.

gusty commented Jan 12, 2018

Guys, you're right, SRTP solve it, though for a limited number of elements.

I have wrote some stuff like that for F#+ but mainly to get lenses for tuples. I agree with @dsyme in that accessing the tuples by properties (or even by fst and snd) is not generally a good idea. But sometimes when writing generic code you need to do stuff like that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment