Skip to content
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

with val syntax sugar for more complex types #707

Open
jiribenes opened this issue Nov 22, 2024 · 2 comments
Open

with val syntax sugar for more complex types #707

jiribenes opened this issue Nov 22, 2024 · 2 comments

Comments

@jiribenes
Copy link
Contributor

jiribenes commented Nov 22, 2024

Problem statement

There's no way to unpack more complex types the using with val _ = ... syntax sugar.

Motivation

When working with stream, I tried to do something like:

def main() = {
  with val (i, x) = [(1, 'a'), (2, 'b'), (3, 'c')].foreach;
  println(show(i) ++ ": " ++ show(x))
}

in order to unpack the tuple.
However, that's wrong since this sugar would imply that foreach takes two arguments
as it desugars to something like:

...foreach { (i, x) => ... }

But the correct diet, sugar-free version is the following:

def main() =
  [(1, 'a'), (2, 'b'), (3, 'c')].foreach { case (i, x) => 
    println(show(i) ++ ": " ++ show(x))
  }

Possible and impossible workarounds

I tried to remedy this by using Tuple2(i, x) explicitly, but that reports a parse error:

def main() = {
  with val Tuple2(i, x) = [(1, 'a'), (2, 'b'), (3, 'c')].foreach;
  //             ^ Expected = but got (

  println(show(i) ++ ": " ++ show(x))
}

Similarly if I try to use a custom type:

record Pos(i: Int, x: Char)
def main() = {
  with val Pos(i, x) = [Pos(1, 'a'), Pos(2, 'b'), Pos(3, 'c')].foreach;
  //          ^ Expected = but got (

  println(show(i) ++ ": " ++ show(x))
}

What does work is the following:

def main() = {
  with val tup = [(1, 'a'), (2, 'b'), (3, 'c')].foreach;
  val (i, x) = tup;
  println(show(i) ++ ": " ++ show(x))
}
@jiribenes
Copy link
Contributor Author

I'm also not 100% sure that we want this feature, but it's very helpful in the zip example in the PR text of #705.

@jiribenes
Copy link
Contributor Author

Here's the code responsible for parsing with val ...:

def withStmt(): Stmt = `with` ~> peek.kind match {
case `val` =>
val params = (`val` ~> peek.kind match {
case `(` => valueParamsOpt()
case _ => List(valueParamOpt()) // TODO copy position
})
desugarWith(params, Nil, `=` ~> expr(), semi() ~> stmts())

where as here's the code responsible for parsing val (a, b) = ...:

def matchLhs() =
`val` ~> matchPattern() ~ manyWhile(`and` ~> matchGuard(), `and`) <~ `=` match {
case AnyPattern(id) ~ Nil =>
val binding = stmt()
val valDef = ValDef(id, None, binding).withRangeOf(startMarker, binding)
DefStmt(valDef, { semi(); stmts() })

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

No branches or pull requests

1 participant