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

Reverse selection and slice operators #518

Closed
5 of 6 tasks
financial-engineer opened this issue Nov 14, 2016 · 8 comments
Closed
5 of 6 tasks

Reverse selection and slice operators #518

financial-engineer opened this issue Nov 14, 2016 · 8 comments

Comments

@financial-engineer
Copy link

financial-engineer commented Nov 14, 2016

Reverse selection and slice operators

I suggest adding the ![] reverse selection operator, ![ .. ] reverse slice operators for lists, arrays and user-defined types representing a collection of values. These language features will be in great demand and open a much more intuitive and simple way to interact with the data encapsulated in a type if values have to be accessed in a reverse order.

The .[] forward selection operator and .[ .. ] forward slice operator, starts counting from the beginning, while the ![] reverse selection operator and ![ .. ] reverse slice operator should start from the end. Indexing always starts at zero (except for non-zero-based arrays).

For example, let array1D : int[] = Array.init 10 (fun i -> i). Therefore, array1D = [| 0; 1; 2; 3; 4; 5; 6; 7; 8; 9 |], array1D.[0] is the first item of array1D, while array1D![0] is the last item, that is array1D.[9].
The forward and reverse slice operators are intended to concisely select multiple items from a collection. So, array1D.[0 .. 3] selects the first four items [| 0; 1; 2; 3 |], while array1D![0 .. 3] selects the last four items in a reverse order [| 9; 8; 7; 6 |].

Language users should be able to add support for reverse selection and slicing by implementing the reverse indexer (as the ReverseItem property with get, set) and reverse slicer (as the GetReverseSlice method) similar to the Item property, GetSlice method used for implementing forward selection and slicing for user-defined types in F#.

For example,

type NumberString() =
   let mutable lst = [| "one"; "two"; "three"; "four"; "five";
                             "six"; "seven"; "eight"; "nine"; "ten" |]
   member this.ReverseItem
      with get(index) = lst![index]
      and set index value = lst![index] <- value
   member this.GetReverseSlice(from : int option, upto : int option) =
     let from = defaultArg x 0
     let upto = defaultArg y (lst.Length - 1)
     lst![ from .. upto ]

The existing way of approaching this problem in F# is writing boilerplate helper functions to achieve the same result.

Pros and Cons

The advantages of making this adjustment to F# are

  • Improvements of code readability and succinctness;
  • Avoidance of the nasty off-by-one errors and just the verbosity of computing the end of a range.

The disadvantages of making this adjustment to F# are

  • Potential for slight confusion over the difference between the ! for reference cells and the !.[], !.[ .. ] operators for reverse selection and slicing. But in modern F# nobody needs to use reference cells as much as with previous versions of F#, as a single let mutable is used as an alternative. The syntax for mutable values does not include the ! symbol. So, the disadvantage of making this adjustment to F# is neglectable.

Extra information

The ! reverse selection operator exists in Cryptol, a programming language for cryptography used by some aerospace and defense contractors in the United States.

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

Related suggestions: no

Affadavit (must be submitted)

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").

Please tick all that apply:

  • This is not a breaking change to the F# language design. It does not affect existing codebases.
  • I would be willing to help implement and/or test this
  • I or my company would be willing to help crowdfund F# Software Foundation members to work on this
@smoothdeveloper
Copy link
Contributor

Not 100% sure about the syntax but definitely something useful, I was wondering if I could use negative values and it results in out of bound exceptions.

Are there references to other languages supporting this feature for comparison?

@financial-engineer
Copy link
Author

financial-engineer commented Nov 15, 2016

negative values results in out of bound exceptions

  • That's a good idea for zero-based collections (especially zero-based arrays), smoothdeveloper.

Are there references to other languages supporting this feature for comparison?

I know that this feature exists in Cryptol only. It particularly useful for developing cryptographic algorithms. You take the needed items from a collection in a reverse order (in a single-step operation), and do not bother about how to achieve that step-by-step.

@Rickasaurus
Copy link

Some form of this would be useful I think. It begs for a custom little indexing DSL. I've also often wanted to be able to index with a collection of indices (like in matlab) and have functions that return sorted index arrays instead of just a sorted array itself (I've had to paste this into my projects so many times). I work with index arrays a lot as they are very efficient.

I'm not a bit fan of the !, it seems like it would be best if the description of what's happening could be maintained inside the indexer.

@smoothdeveloper
Copy link
Contributor

When working with arrays, it is also frequent to use offset and length rather than inclusive range with current notation. It would be great to have a notation understanding offset and length to avoid the nasty off by one errors or just the verbosity of computing the end of the range.

@financial-engineer
Copy link
Author

I'm not a bit fan of the !

@Rickasaurus
Syntax with the ! symbol is a rational choice (with due regard for the F# language resources: symbols being used with a special meaning in code, keywords).

In my opinion, the reverse selection and slice operators have:

  • To consist of the same number of symbols as the forward selection or slice operators.

No new keyword is needed (something like .reverse.[] should be ruled out entirely); the existing F# keywords are not suitable for this goal either).

  • To contain square brackets in order to look like the forward selection and slice operators .[], .[ .. ]
  • To contain one symbol that differs from the . symbol being used in the forward selection and slice operators.

Which symbols are available on a keyboard for this goal? Alphabet letters have to be excluded entirely for an obvious reason. Please look at your keyboard. The following symbols (~, !, @, #, $, %, ^, &, *, (, ), -, +, =, [, ], |, \, /, ;, ., ", <, >, *, +) are available, but the usage of some symbols would be impossible or misleading due to their current roles in F# (~, @, (, ), -, +, =, [, ], |, ;, ., ", <, >, *, +) or their meanings in plain English text (#, $, %). So, which symbol is left? Only the ! symbol is suitable for our goal. Іn addition, it contains a dot implying it's a selection or slice operator, and a vertical bar indicating that it is not a forward selection or slice operator, but a yet another, reverse selection or slice operator ![], ![ ..].

@cartermp
Copy link
Member

cartermp commented Dec 7, 2016

I'm used to this from Python where - is used to go backwards. I'm not sure if it's just due to familiarity, but I rather like that approach instead of !.

However, the overall idea is one I definitely support. It's a nice utility that I could see people using.

@dsyme
Copy link
Collaborator

dsyme commented Mar 1, 2017

I'm used to this from Python where - is used to go backwards. I'm not sure if it's just due to familiarity, but I rather like that approach instead of !.

Agreed

@dsyme
Copy link
Collaborator

dsyme commented Mar 1, 2017

This is a good and valuable discussion. I'm merging this with this issue: #358

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants