-
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
Pattern matching spans of chars against constant strings #1351
Comments
I am personally not a huge fan of introducing intrinsics to the compiler it should know of to be able to optimize it. Implicit conversion looks better tbh, but will involve additional hidden conversions/allocations. Also, confusing from the usability/type system perspective - "Why do I compare Span to string"? |
Hmm, it would indeed involve hidden invocation of
While I can sympathize with this perspective somewhat, once you know what spans are and are for, then it's annoying not to be able to mix and match spans created from strings and strings themselves — C# enables this on purpose by using Separately, while it's not exactly the same, there is already some precedent in the language for syntactic crossover between string-like things and array-like things: // Looks like a string...
match "abc"B with
// ...But it's actually an array.
| [|0x61uy; 0x62uy; 0x63uy|] -> printfn "Matches."
| _ -> printfn "Doesn't match." |
From a design perspective, it's also nice as a user when the easy thing is also the fast/correct thing. |
Yeah, I meant if we do type directed the other way (span -> string) for some cases, where we can't (?) do AsSpan.
Yeah, it can just be somewhat confusing for some people, I suppose. |
I suppose it's a tradeoff - do exactly what user wrote (or close to it) versus try and rewrite/optimize things. We already do both, so no really huge directional change. I suppose it's up to @dsyme now - whether we want to do more with spans (and byreflikes in general), since it's clearly where Roslyn is going (and clr in general). |
I don't understand this semantically. |
Yeah, I get that it "is" not a string, and that it might not "feel" F#-y if you focus on the current type implications of string literals rather than viewing them as a shape or pattern of
The whole point of spans is to serve as windows into contiguous stretches of memory — and a string literal is just special syntax for a stretch of contiguous Sure, when a string literal is used as an object, an object is created to point at that stretch of I do understand that the usage of So in my mind the change here doesn't imply some new type equivalence between spans and strings, but rather specifically enables treating string literals as patterns representing spans of characters against which, well |
Proposal
I propose that we allow pattern-matching values of type
ReadOnlySpan<char>
andSpan<char>
against constant strings.Compare the equivalent C# proposal (implemented in C# 11).
We would do this by first automatically generating calls to
System.MemoryExtensions.AsSpan
on a constant string being matched against, and then by passing the resulting span and the input span to the appropriateSystem.MemoryExtensions.SequenceEqual
overload.The existing way of approaching this problem in F# is...
Use string slicing instead of span slicing. This allocates a new string.
Use a series of
if
-then
-else
expressions instead of pattern-matching.Define and use an active pattern like:
I almost didn't include this, because I'd rather not need to think to do this — and (in my experience) most people would not think to. Even if an equivalent active pattern were included in FSharp.Core, it would not be very discoverable.
Notes
We would not change the type inference rules for string patterns — the inferred type for the pattern input of a string literal pattern would still be
string
.As in the C# implementation, I think we would want a compile-time error for matching against
null
:Any named pattern bindings should still have the input (span) type:
Pros and cons
The advantages of making this adjustment to F# are
The disadvantages of making this adjustment to F# are
Alternatives
Type-directed
[…]
syntax (Type-directed resolution of [ .. ] syntax #1086) could theoretically subsume this, although when the underlying thing being sliced is a string, I think allowing matching against string literals still has a readability advantage. C# supports both, for what it's worth:Extra information
Estimated cost (XS, S, M, L, XL, XXL):
Related suggestions: (put links to related suggestions here)
This could potentially be viewed as an extension of Auto-upcast values when type information is available #849 (see discussion of
op_Implicit
in FS-1093).It's pretty common today to pattern-match multiple strings at once using tuple syntax, like
If we make the change from this proposal, doing the same with spans would not work without additional changes to the compiler (compare Lift byref generics restrictions for inline functions #688, Support byref-like parameters (e.g., Span) in local functions that don't capture and are only invoked #887, Special-case raising an exception with byrefs #872, etc.):
Affidavit (please submit!)
Please tick these items by placing a cross in the box:
Please tick all that apply:
For readers
If you would like to see this issue implemented, please click the 👍 emoji on this issue. These counts are used to generally order the suggestions by engagement.
The text was updated successfully, but these errors were encountered: