9

According to this answer https://stackoverflow.com/a/8001065/1586965 we can do this in Scala:

val _ = 5

Now I understand the point of ignored parameters in lambda expressions, but I cannot really imagine examples where I would ever want to declare a variable that by definition I cannot reference. The only example I can think of is being lazy about naming implicit values, e.g.

implicit val _: MyNumeric = ...
...
class A[T : MyNumeric] {
...

Is this the only use case? Am I missing something?

If it is the only use case, shouldn't the compiler/IDE give a warning/hint when the val is not implicit as it is utterly pointless?

Clarification

By variable/value I mean a single one, not one that is part of an extraction declaration.

Community
  • 1
  • 1
samthebest
  • 30,803
  • 25
  • 102
  • 142
  • Your clarify says you don't mean patterns, but the argument at the end of this ticket is that it's a pattern. https://issues.scala-lang.org/browse/SI-7691 I think it's a name, not a pattern, and would require special spec; but still interesting. – som-snytt Sep 11 '14 at 13:42
  • Someone answered with for-comps like here (for uncontrived example): https://github.com/scala/scala/blob/v2.11.2/src/library/scala/Responder.scala#L44 and similarly `for (i <- g; _ = v)` – som-snytt Sep 11 '14 at 13:51

3 Answers3

18

I don't think that this is a feature at all. In any case, it is not an "ignored variable". By which I mean that if val _ = 5 really introduced an unnamed value, then you could declare as many as you want in the same single scope. Not so:

scala> object Test {
     |   val _ = 5
     |   val _ = 7
     | }
<console>:9: error: _ is already defined as value _
         val _ = 7
         ^

From the error message it seems clear that what really happens is that the value is actually named _ (which I'd call a quirk of the compiler that should be fixed). We can verify this:

scala> object Test {
     |   val _ = 5
     |   def test() { println( `_` ) } // This compiles fine
     | }
defined object Test

scala> Test.test()
5

As for the possible use of preventing a value discarding warning (as shown in som-snytt's answer), I'much prefer to simply return an explicit Unit. This looks less convoluted and is even shorter:

def g(): Unit = { f(); () }

as opposed to:

def g(): Unit = { val _ = f() }    
Régis Jean-Gilles
  • 32,541
  • 5
  • 83
  • 97
  • Hmm, yes appears its a quirk, not a feature, but I like it and prefer the `val _ = f()` as its only one line. I would never put two lines onto 1 by using semicilons. – samthebest Sep 11 '14 at 09:44
  • I much prefer this answer – Michael Lafayette May 16 '16 at 05:21
  • The fix you requested is in 2.13, so `val _` does not introduce a variable; underscore in backticks still works. The usage `implicit val _` is (temporarily?) broken. – som-snytt Jan 31 '19 at 18:48
10

It uses a value.

$ scala -Ywarn-value-discard
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_11).
Type in expressions to have them evaluated.
Type :help for more information.

scala> def f() = { println("I ran.") ; 42 }
f: ()Int

scala> def g(): Unit = { f() }
<console>:8: warning: discarded non-Unit value
       def g(): Unit = { f() }
                          ^
g: ()Unit

scala> def g(): Unit = { val _ = f() }
g: ()Unit

scala> g
I ran.

scala> 

To verify, it also doesn't warn under -Ywarn-unused.

som-snytt
  • 39,429
  • 2
  • 47
  • 129
  • 2
    Assignments always evaluate to `Unit` in Scala. You get the exact same result if you use `val foo` instead of `val _`, no? – Jörg W Mittag Sep 11 '14 at 10:54
  • 2
    @JörgWMittag The block still gets unit value inserted at the end as a result expression, but with the assignment, you're not discarding a value; with underscore, you haven't racked your brain to invent an identifier. A stretch to call this a use case. – som-snytt Sep 11 '14 at 13:24
6

The other use case (that I can think of) is related to extraction (and is called out under "Wildcard patterns" in the linked answer):

val getCartesianPoint = () => (1, 2, 3)
// We don't care about the z axis, so we assign it to _
val (x, y, _) = getCartesianPoint()

val regex = "(.*?)|(.*?)|?.*".r
// Really, any unapply or unapplySeq example will do
val regex(_, secondValue) = "some|delimited|value|set"
Community
  • 1
  • 1
Sean Vieira
  • 155,703
  • 32
  • 311
  • 293
  • Correct, but accepting the other answer as it more closly fits my question. Im going to add a clarification to my question. – samthebest Sep 11 '14 at 05:21