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

Ternary equality / between comparator #676

Closed
EBrown8534 opened this Issue Jun 19, 2018 · 7 comments

Comments

Projects
None yet
4 participants
@EBrown8534

EBrown8534 commented Jun 19, 2018

Ternary equality / between comparator

I propose we add support for the "between" ternary syntax: a < x < b. This should support < and <=.

The existing way of approaching this problem in F# is to write a multi-expression comparison: a < x && x < b, which is typically written as x > a && x < b.

Pros and Cons

The advantages of making this adjustment to F# are a more succinct and legible syntax for testing a value between two other values.

The disadvantages of making this adjustment to F# are:

  • I'm pretty sure it is a lot of work, F# currently has no ternary expressions that I'm aware of, so this is a brand new concept to the specification, language, and compiler;
  • It's specific to < or <=, so it's only beneficial in highly limited cases;
  • The benefits are not substantial, the x > a && x < b syntax is only slightly longer;
  • Being a ternary operator, composition support will be difficult to evaluation and include (is it left-to-right, right-to-left, or middle-outward?);
  • Overloading / overriding the operator would become highly complicated;

Extra information

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

Related suggestions: #675

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

This comment has been minimized.

abelbraaksma commented Jun 19, 2018

This is not a breaking change to the F# language design

I'm not sure this applies. Taking your suggestion literally (that is, without suggesting updated syntax), the following will lead to a different result:

true > false && false > false  // original syntax for "between", yields false
true > false > false           // new syntax for "between" currently yields true, but should then become false

The other thing about "breaking change" being the one you already mentioned: ternary operators are now not allowed, so it will require careful thinking finding out whether chained operators could now suddenly be redefined as ternary (think x |> y |> z). One way forward might be to require a special syntax or designator for ternary operators.

Note also that ternary operators are rare, most languages (though notably not F#) support only the .. ? .. : .. ternary conditional operator.

@EBrown8534

This comment has been minimized.

EBrown8534 commented Jun 19, 2018

I don't disagree at all.

As a regular, non-expert, user of F#, I think this whole idea is "meh", I don't think it's something that needs to make it in the spec. (I mostly proposed it so that we can have the discussion on it now, and get it out of the way.) Being on the low-end of the expertise spectrum, it really wouldn't convince me all that much to use it.

While it adds a little value (arguable), some of the situations you mentioned to create problems. In Slack, Diego Esmerio (@Nhowka) mentioned the following active pattern that does the same thing:

let (|Between|_|) a b x =
  let m = min a b
  let n = max a b
  if  x > m && x < n then
    Some Between
  else
    None

let test = function
  | Between 0 5 -> printfn "Passed"
  | _ -> printfn "Outside range"

test 4
test 8

Personally, I think this would be a far better feature to include in the core F# spec, and would alleviate both issues much more cleanly and idiomatically. With this pattern, I wouldn't need to have | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10, I can use Between 0 11. (Maybe we make it inclusive, instead of exclusive, for better support of ranges.)

@abelbraaksma

This comment has been minimized.

abelbraaksma commented Jun 19, 2018

Yes, it is trivial to add the Between active pattern. Though when adding it to FSharp.Core we'll need to answer things like "is it inclusive, exclusive, left-inclusive?" and "How do we treat NaN?" and "Is -INF inclusive in the range from -INF?" and I'm sure you can think of others ;).

As an alternative, have a look here, it has two operators defined that act as 'between": http://www.fssnip.net/9y/title/Between-operators

@EBrown8534

This comment has been minimized.

EBrown8534 commented Jun 19, 2018

@abelbraaksma I was actually thinking about that this morning, because I added it to my own extensions library. I went with two items:

  • Between a b: matches if the value is inclusively in the range (x >= a && x <= b);
  • BetweenExc a b: matches if the value is exclusively in the range (x > a && x < b);

But, alas, it still doesn't answer the +/- INF or NaN questions, really. It accepts however >= / <= will treat them. It also complicates usage a bit, but at least it helps with my use-case, and allows me to do what I wanted without complicating things any further than necessary.

I'd prefer to see this type of a pattern-match capability built-in once we nail those questions down, because I think it's immensely more useful in this scenario.

@cartermp

This comment has been minimized.

Member

cartermp commented Sep 10, 2018

Since this is a breaking change and doesn't seem to dramatically improve the lives of most F# programmers, I doubt this would be taken.

@EBrown8534

This comment has been minimized.

EBrown8534 commented Sep 11, 2018

@cartermp To be fair, the only argument I would make the opposite is that F# is a language of conveniences, no matter how small. Something like this adds another convenience to the language. (Not that such a reason justifies it.)

I'm on the fence about this anymore, I think it would make the syntax for such things clearer, but it's not something I use (or would) a lot anyway.

@dsyme

This comment has been minimized.

Collaborator

dsyme commented Oct 12, 2018

Closing this, I agree we won't be doing this one, it's in the category of "things we considered in F# before and decided against"

@dsyme dsyme closed this Oct 12, 2018

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