match outputs::<Option<String>>() {
opt @ Some("example") => {
assert_eq!(opt, Some("example")); // Error, mismatched types
},
...
}
I don't understand asking to start with something which hides semantics: while terseness can come in handy when a pattern has become pervasive enough, people need to have integrated the "verbose" pattern first (I'm pretty sure there is a quote out there that phrases this better). Many programmers already struggle with patterns, and using sugar to "hide" its complexity usually backfires the moment a more subtle situation happens, such as the one above. Granted, deref
, is a quite verbose annotation (I wouldn't like having to write deref "…" | deref "…"
etc.), but I do think that starting with some sigil is the best way to make the whole process more likely to be accepted and integrated (the language would greatly benefit from the feature being added in some form, and I find that jumping straight to sugar will just slow the whole thing down due to all these corner cases and clarity considerations).
Then, once the need for sugar outweighs the effort needed to clarify and handle all the corner cases that it causes, as well as the surprising situations that it leads to, a follow-up change could be considered, suggested, and discussed.
For instance, I personally see that opt @
, in the example above, must necessarily bind to the original expression (hence causing the type error), whereas other programmers have expressed that the "natural" situation there for them is for opt @
to bind to the deref'd pattern (and thus have opt: Option<&str>
).
- For those thinking that with the latter interpretation everything Just Works™, and that I am the one wrong, consider
enum NonGeneric { Some(String), … }
, and tell me what the type of opt @ NonGeneric::Some("foo")
would then be.
The situation with no sigils is thus ambiguous and not yet intuitive, so it is, at the very least, a decision that should be left for a follow-up change: let's first have deref patterns with some sigil / annotation for a few months before discussing about further changes.
FWIW, taking &
, a 1-long sigil, to represent deref, the examples I've mentioned are less confusing / suprising, and the incurred "sigil noise" remains low:
match outputs::<Option<String>>() {
opt @ Some(&"example") => {
assert_eq!(opt, Some("example")); // Error, mismatched types
},
...
}
// as well as:
opt @ NonGeneric::Some(&"example") => …
// ^^^^^^^^^^
// hints at `Some(impl Deref<Target = str>)`,
// which is correct, contrary to `Some(&str)`.