-
Notifications
You must be signed in to change notification settings - Fork 21
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
negation patterns #793
Comments
This is how it will look:
match 5 with
| !(4 | 5) -> true
| 4 -> false
| 5 -> bool (Console.ReadLine())
let a = (<) 3 // 3 < x
let b =
function
| < 3 -> true // x < 3
| _ -> false Range patterns: Same as how you would construct a range. match x with
| 0..13 -> 13
| 14 -> 14
| 15..System.Int32.MaxValue -> 15 |
Given the existence of Out of the suggestions, I would think that |
It's not used this way in patterns, is it? |
The existing |
|
#569 isn't really realistic and is not on the docket for F# 5.0. That issue was formulated based on a misunderstanding of language defaults with the LangVersion flag. |
I would agree with staying with known semantics. It is typically a bad idea to change semantics of previously chosen operators. Having Though there's the small chance someone has Though I do believe there is a case to be made for |
I can understand some of the extra flexibility introduced by this (especially the not pattern), but I really don't buy into the idea that we should do this because "c# has it". Language features should be judged on merits of whether they are suitable for F# alone - I don't want F# to be a clone of C# (or vice versa), and a goal of adding features to F# shouldn't be (IMHO) that it will make migrating from C# easier / it will be less work to learn the language. |
I find that using 'not' instead of '!' is s strength of F# as it is more clear when reading and easier to spot when scanning for the source of a bug, '!' is too easy to miss. |
You can sort of already do this...
Then
|
shall we also consider pattern matching in if (o is T t) {
// do something with t
} |
@yatli Personally, I find type test patterns to frequently be signs of a poor underlying design (too much OO emphasis). I'd rather that pattern not end up in F# (esp. in a form that seems to encourage its use). Do you see this as useful for any other patterns? |
For example, a shortcut equivalent for: match o with
| T(t) when t > 3 -> // do something with t
()
| _ -> ()
//==========
if o is T(t) && t > 3 then
()
//if type test is required, cast our usual spell:
if o is :? T as t then
// do something with t
// edit: active pattern + if could be cool too
if kv is KeyValuePair(k, v) && k = 1 then ...
Pros:
Cons:
|
I don't spot ternary operators in your proposal, but other proposals with actual ternary ops (i.e., similar to
I think you mean "again"? If so, I'm afraid the inverse is rather true. F# checks if your matches are complete, but cannot do so for if-statements. You could write
Not sure what you mean here. I don't see why normal patterns, with exhaustion testing, isn't good for DSL's. As an aside, there's an age-old proposal that has recently been resurrected (see discussion here: #222 and RFC draft here: fsharp/fslang-design#402). These follow your idea to some extend, but instead of turning a |
No :) I mean for Also, I'm always not very confident about how the compiler would arrange multiple match conditions.
That's not my point. What I mean is that if we allow pattern matching in let (|GOOD|BAD|) x = ...
if x is GOOD then ...
could be convenient, but I think pattern matching in Sorry if I'm off-topic, I can move this into a new proposal. |
That may be better, I agree.
It does, but nothing stops you from writing Don't forget that matching against DU's is (typically) a table-lookup in IL. Which means that it requires only one evaluation. With
And how would this work when the active pattern has multiple arguments? But you may be onto an interesting idea, even though I am not convinced it is worth the effort, or that it solves enough use-cases to get traction. But I must admit that I too sometimes would have liked writing But I digress, let's set up a different topic for this. |
My proposed resolution:
|
Nah, it was a misapplication of the defaults for the feature in the Visual Studio toolchain 😛 More seriously, it's really a shame we still don't have a way to deprecate anything even over 5 or 10 year timeframe, for freshly written code.... |
I’m mostly in agreement (as usual) with Don’s ... let’s call “taste” — especially with regards to ternary expressions. However, I’m curious what benefits are imparted from a specific syntax for negation in matching (as opposed to just defining a partial active pattern)? Is there some optimization the compiler couldn’t otherwise perform? |
IIUC not patterns are not boolean negation, but rather they say "this pattern match must fail", e.g.
Thus they interact with completeness checking, for example. I first saw them in "Alice ML" though I'm not sure where they existed before that |
Ahh... thanks, @dsyme. That actually makes perfect sense. Cheers! |
I've renamed this to negation patterns. I've never used a language with negation patterns and while I appreciate their declarative nature I'm curious if they actually make pattern matching simpler to read and understand. Or does the person reading the code have to invert the negation in their head? |
I mean it feels like something really explicit may be better:
Also, we have to be aware negation of matching is pretty corrosive w.r.t. software engineering - the equivalent of partial |
It's useful in branch reordering and indentation elimination. match i with
| 1 ->
match j with
| 2 -> ...
| _ -> ()
| _ -> () match i with
| not 1 -> ()
| 1 ->
match j with
| not 2 -> ()
| 2 -> ... |
Yes, it's useful, but is it easy to read and understand? I'm not at all sure |
What about eliminating the need to define inverse active patterns for existing active patterns? |
@Happypig375 I'm happy for us to list out the advantages. The question I'm raising is the different - that is, is it simpler to read and understand for the non-code author, the beginner? It might be convenient for the code author, and hard to understand for everyone else. Pattern matching already contorts the mind - it makes people read code as "decomposition of information" rather than "production of information" (expressions). That's intrinsic, though I'm very aware of this when I look at pattern matching in C#, for example. Negations also contort the mind - they make you look at program text "the opposite way around". I find reading negations of boolean logic really difficult. Putting these together really concerns me - we'd be adding a second level of mind contortion and people might use it because it's cute. I'd really like to understand how we can get evidence about that. And it would aboslutely motivate something really explicit lile |
@Happypig375 your 2 examples aren't equivalent. An example of equivalent code in 2 syntaxes where there is an advantage of using Edit... unless you meant that putting |
Hmm, I'll come back when I see that not-patterns really add readability. @charlesroddie |
You can currently do this without a warning: match 0 with
| 1 -> 2
| _ ->
3 But I think it's a bug and should be changed to give an indentation warning on |
This is by design - several constructs allow linear non-indentation by choice, e.g. // non-indenting conditional "early return"
if e1 then e2 else
e3
// non-indenting matching
match e1 with
| p1 -> e2
| _ ->
e3
// non-indenting SQL-like comprehensions for query syntax
for x in foo do
for y in goo do
something |
My proposed resolution was here: #793 (comment) However, in retrospect I still am deeply concerned that negation patterns "flip the mind" in awkward ways that make code much harder to read and understand, even if theoretically more maintainable. I don't know what it is, but as soon as I read a negation pattern my heart rate jumps and I feel stressed, like my brain needs to start thinking the other way around, negatively instead of forwardly. Given this, and the very large implementation cost, I think I'm just going to close this whole issue. There are some other suggestions to enforce exhaustive matching on particular types and those seem better I think |
I propose we add negation patterns, that is patterns that say "this pattern match must fail", e.g.
These interact with completeness checking, for example. Variables cannot be bound inside the negation pattern.
Pros and Cons
The advantages of making this adjustment to F# are
The disadvantages of making this adjustment to F# are
Extra information
Estimated cost (XS, S, M, L, XL, XXL): M
Related suggestions: (put links to related suggestions here)
#661 Comparison pattern - Declined
#264 Range pattern - Declined
Affidavit (please submit!)
Please tick this by placing a cross in the box:
Please tick all that apply:
The text was updated successfully, but these errors were encountered: