-
Notifications
You must be signed in to change notification settings - Fork 30
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
SIP-53 - Quote Pattern Explicit Type Variable Syntax #59
SIP-53 - Quote Pattern Explicit Type Variable Syntax #59
Conversation
3f594a7
to
388476d
Compare
After thinking about this proposal more deeply I have some concerns:
case '[ (t, t, t) ] => might seem handy, it would introduce inconsistency with regard to how this works with non-quote-based match expressions. E.g. neither of the snippets below compiles def mergePair(pair: (Int, Int)) = pair match
case (x, x) => x type MergePair[P <: (Int, Int)] = P match
case (x, x) => x To keep things consistent I think we would have to make them work too. As that would extend the scope of the SIP, I would suggest extracting the possibility to reuse a pattern variable (also when matching on a non-quote expression or on a type) to a separate SIP.
case '[ type t; List[`t`] ] => f[t]
case '[ type tail <: Tuple; *:[Int, `tail`] ] => g[tail] the auxiliary type declarations are redundant. Could you instead give some examples where this new functionality would be actually useful? From what I understood such syntax would only make sense to specify some additional type bounds which cannot be inferred, though in most cases that would be just syntactic sugar over type extractors. The only thing that I didn't manage to express with type extractors seems to be |
Both cases An equivalent usage with a normal Scala pattern could be |
In #59 (comment) there is some misleading nomenclature. These type declarations |
Sorry for the confusion in the terminology. These expressions were not mentioned in the document so I would suggest introducing them there for clarity. My general concern is that in the context of For instance: I am aware we cannot treat term and types in exactly the same way but being able to manipulate types analogically to terms seems to make operations on types more intuitive for users and easier to reason about, as show above in the example with Also, one of the features of pattern matching that makes it so convenient and intuitive to use is the duality of construction and deconstruction. So, e.g. Foo(1, 2) match
case Foo(x, y) => Foo(x, y) would return '{ type t; 1 } match
case '{ type t; 1 } => don't seem to work. I suppose some of these peculiarities are there for a reason and they might make some more sense if analyzed from a different perspective and explained/documented in a better way. However, in that case, we should first at least document these things properly. Secondly, if there's anything that could be regularized from the syntactic point of view, we should do that too before extending the syntax. |
There are possibly larger changes that could be proposed to improve the consistency / usability of quoted patterns. However this SIP is a relatively small iteration on the current syntax, it proposes two changes:
Both makes sens to me, so I can recommend accepting this SIP. |
@Kordyjan and @chrisandrews-ms could you please review this proposal and comment here? |
I also recommend accepting this SIP |
@Kordyjan what is your recommendation regarding this proposal? |
Sorry for not giving my recommendation earlier. |
This SIP only adds the ability to explicitly define the type variables. It will not remove any functionality. |
IMO, this SIP needs a (Pre-SIP) discussion thread on contributors before we can vote on it. |
What would be discussed in a Pre-SIP? The syntax of type variable definition was set before 3.0 as it is the same as in expression patterns (same holds for the semantics). The only addition is the simplification to be able to use refer-to type variables without backticks ( I could open a pre-SIP about removing backticks and maybe split this SIP into two. |
If I understand this proposal correctly, explicit type variables in type patterns The example usage for this feature in the document is: case '[ type tail <: Tuple; *:[Int, tail] ] => g[tail] But the definition of case '[ *:[Int, tail] ] => g[tail] This would mirror how type patterns in regular term-level pattern matching works: case x: *:[Int, tail] => ... // In this expression, we have tail <: Tuple This does make it a bit harder to restrict bounds further than what can be inferred, although it could be achieved with something like: type ListOfInt[T <: Int] = List[T]
// ...
case '[ ListOfInt[t] ] => Again this has the advantage of not mixing type definition syntax and type reference syntax in an unprecedented way, and of working in regular term-level pattern matching. WDYT? |
Quote type variable inference is one of the problematic features that made us realize we absolutely needed to be able to write bounds explicitly. We made the mistake of adding type inference of type variable bounds to some simple cases, such as is Removing quoted type variable bound inference is the subject of a future SIP. |
What are the issues with bound inference? |
|
||
```scala | ||
case '[ type t; List[`t`] ] => f[t] | ||
case '[ type tail <: Tuple; *:[Int, `tail`] ] => g[tail] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to specify whether semicolon inference works here too:
case '[
type tail <: Tuple
*:[Int, `tail`]
] => g[tail]
If we really need a way to define type bounds inline in quoted type patterns, why don't we consider a slightly different syntax to avoid the precedent of case '{ type tail <: Tuple }[ *:[Int, `tail`] ] => g[tail] or case { type tail <: Tuple }'[ *:[Int, `tail`] ] => g[tail] instead of case '[ type tail <: Tuple; *:[Int, `tail`] ] => g[tail] ? Even though what I'll write next would be out of scope of this SIP, the potential syntaxes shown above seem to open some more new possibilities towards making the general syntax of pattern matching more expressive and uniform, e.g. 1 ) case '{ type t <: Tuple; $x: `t` } => f[t](x: Expr[t]) could be treated as syntactic sugar for case '{ type t <: Tuple }{ $x: `t` } => f[t](x: Expr[t]) or case { type t <: Tuple }'{ $x: `t` } => f[t](x: Expr[t]) with the actual matched expression 2 ) case { val t }(t, t, t) => could be a shortcut notation for case (t1, t2, t3) if t2 == t1 && t3 == t1 => |
After a debate, the SIP committee voted and decided to accept the proposal. |
@Kordyjan could you elaborate on which kind of specification should be enhanced. Currently we have the high level documentation in macros.md#quote-pattern-matching. Is there anything specific that was found missing from there? Or is it the documentation of syntax.md? Or should some other kind of specification be added? |
During the discussion, we were unaware of this documentation, as it is different and more thorough than what can be found in the current reference. For me this documentation is satisfying. @odersky, @sjrd & @bjornregnell: You raised concerns about the lack of reference. What do you think about the documentation linked above by @nicolasstucki? |
I was happy with what was there already. It must have been someone else. |
|
It should be done after each stable release (see e.g. scala/scala3#16662, but I couldn’t find how this issue was generated) |
I have not updated the docs in that PR yet. That is the last thing I need to do to finish that PR. I have already updated the docs of the backticks PR scala/scala3#16935. |
I combined the two PRs of the proof of concept into scala/scala3#17362. |
Hey @nicolasstucki, You can find a list of relevant tools here: https://github.com/scala/improvement-proposals/blob/main/tooling-ecosystem.md |
No description provided.