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

`try ()` does not compile #11532

Closed
SrTobi opened this issue May 15, 2019 · 11 comments

Comments

Projects
None yet
5 participants
@SrTobi
Copy link

commented May 15, 2019

When trying to compile the expression (Scala Version: 2.12.8)

try ()

the following error message is given:

illegal start of simple expression
try ()
     ^

Same goes for all tuples in a try (i.e. try (1, 2))

According to the specification this should work:

Expr1 ::=  ‘try’ (‘{’ Block ‘}’ | Expr) [‘catch’ ‘{’ CaseClauses ‘}’] [‘finally’ Expr]
                                  ~~~~

https://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#try-expressions

@SrTobi

This comment has been minimized.

Copy link
Author

commented May 15, 2019

@SrTobi

This comment has been minimized.

Copy link
Author

commented May 15, 2019

also note that try () => () doesn't work either.

@dwijnand

This comment has been minimized.

Copy link
Member

commented May 15, 2019

I think that makes sense, you need

scala> try (() => ())
<console>:12: warning: A try without a catch or finally is equivalent to putting its body in a block; no exceptions are handled.
       try (() => ())
       ^
res0: () => Unit = $$Lambda$1073/204568533@76f856a8
@SrTobi

This comment has been minimized.

Copy link
Author

commented May 15, 2019

Well... either way, the specification is weird regarding try.

Why have ‘try’ (‘{’ Block ‘}’ | Expr) and not just try Expr (like finally, if, etc...)?

This is even ambiguous, because Expr already contains BlockExpr (Expr > PostfixExpr > InfixExpr > PrefixExpr > SimpleExpr > BlockExpr)

Yes, try () => () doesn't make much sense, but I think consistency is more desirable here.
And try (someCall(), someOtherCallThatMayThrow()) finally { println("gc!!!") } makes definitively sense.

@adriaanm

This comment has been minimized.

Copy link
Member

commented May 15, 2019

Thanks for narrowing it down -- that match does indeed look fishy to me. try (1, 2) should parse afaict. I think the grammar for try reflects how it evolved: originally, you couldn't just pass an expression in. This was added in scala/scala@a7ea097, and I guess no one noticed that was wrong until today :-)

@dwijnand

This comment has been minimized.

Copy link
Member

commented May 15, 2019

scala> try (1, 2)
<console>:1: error: ')' expected but ',' found.
       try (1, 2)
             ^
@dwijnand

This comment has been minimized.

Copy link
Member

commented May 15, 2019

The story here is similar to the story of infix methods with multiple arguments (which Scala 3 is addressing).

The workarounds are clarifying parentheses:

scala> try (())
<console>:12: warning: A try without a catch or finally is equivalent to putting its body in a block; no exceptions are handled.
       try (())
       ^

scala> try ((1, 2))
<console>:12: warning: A try without a catch or finally is equivalent to putting its body in a block; no exceptions are handled.
       try ((1, 2))
       ^
res5: (Int, Int) = (1,2)
@SrTobi

This comment has been minimized.

Copy link
Author

commented May 15, 2019

ok thx for clarifying...I was just reworking our parser for try in Intellij, which was not any less wrong 😄, and I thought I'd miss something.

@som-snytt

This comment has been minimized.

Copy link

commented May 17, 2019

There is a PR scala/scala#4400 and duplicate #5887

@som-snytt som-snytt closed this May 17, 2019

@som-snytt

This comment has been minimized.

Copy link

commented May 17, 2019

$ skala

     ________ ___   / /  ___  
    / __/ __// _ | / /  / _ | 
  __\ \/ /__/ __ |/ /__/ __ | 
 /____/\___/_/ |_/____/_/ | | 
                          |/  version 2.12.6-20180410-164619-76b53db

scala> try ()
<console>:12: warning: A try without a catch or finally is equivalent to putting its body in a block; no exceptions are handled.
       try ()
       ^

scala> try (27, 42)
<console>:12: warning: A try without a catch or finally is equivalent to putting its body in a block; no exceptions are handled.
       try (27, 42)
       ^
res1: (Int, Int) = (27,42)

scala> try () => ()
<console>:12: warning: A try without a catch or finally is equivalent to putting its body in a block; no exceptions are handled.
       try () => ()
       ^
res2: () => Unit = $$Lambda$1796/1472031375@39ab5ef7
@som-snytt

This comment has been minimized.

Copy link

commented May 17, 2019

Relatedly, I had forgotten about "name-based catch", which is also addressed in that PR:

scala 2.13.0-RC1> try 42 catch 22
                               ^
                  error: value isDefinedAt is not a member of Int

scala 2.13.0-RC1> :pa
// Entering paste mode (ctrl-D to finish)

try 42 catch new {
  def isDefinedAt(x: Any) = false
  def apply(x: Any) = ()
}

// Exiting paste mode, now interpreting.


try 42 catch new {
             ^
<pastie>:1: warning: reflective access of structural type member method isDefinedAt should be enabled
by making the implicit value scala.language.reflectiveCalls visible.
This can be achieved by adding the import clause 'import scala.language.reflectiveCalls'
or by setting the compiler option -language:reflectiveCalls.
See the Scaladoc for value scala.language.reflectiveCalls for a discussion
why the feature should be explicitly enabled.

try 42 catch new {
             ^
<pastie>:1: warning: reflective access of structural type member method apply should be enabled
by making the implicit value scala.language.reflectiveCalls visible.
res1: AnyVal = 42

@SethTisue SethTisue removed this from the Backlog milestone May 17, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.