scala / scala-library-next

backwards-binary-compatible Scala standard library additions
Apache License 2.0
67 stars 17 forks source link

Proposal: Add void to Predef #43

Closed BalmungSan closed 3 years ago

BalmungSan commented 3 years ago

I have found this little helper (courtesy of Rob) to be very useful. Especially when you enable compiler options like -Wvalue-discard or -Wunused:implicits (and friends)

@inline final def void(args: Any*): Unit = (args, ())._2

While adding this into all of my projects is not really "painful" I would like if this would be part of Predef.

So I thought this would be the right place to start a discussion about if it would be worth it to add it; and if such addition could be done here until 3.1?

SethTisue commented 3 years ago

the main previous discussion I can think of is https://github.com/scala/scala/pull/9161 , perhaps there are others

given that both val _ = ... and ...: Unit work (don't they?), I'm not sure we need a third way to do this? but offhand I don't recall all twists and turns in past discussions

SethTisue commented 3 years ago

(args, ())._2

going through Tuple2 seems like an unnecessary allocation?

Daenyth commented 3 years ago

: Unit doesn't work when using -Ywarn-value-discard.

BalmungSan commented 3 years ago

given that both val _ = ...

AFAIK there are some problems with that one. First, it can not be reused like you can not (or couldn't in previous versions) to do this

val _ = foo
val _ = bar

Also, I remember there was something funny about the way it was treated by the compiler. I believe it was @tpolecat the one that explained that to me. (I believe the funny thing was that it couldn't be reused, but maybe there was more, I can't remember tbh sorry)

and ...: Unit

Actually didn't know about this one, a quick test in a shell seems to work but will try latter on a real project using sbt-tpolecat.

I'm not sure we need a third way to do this

A plus is that this one also works for unused values.

going through Tuple2 seems like an unnecessary allocation?

Yeah, also the Seq of the varargs. I was also planning to open a discussion if it would be possible that the compiler treats such function especially and simply replaces it with a no-op. But, first I wanted to see if more people find it useful.

eed3si9n commented 3 years ago

On Scala 2.12.12 there isn't a great solution: spurious "a pure expression does nothing" warning (awkward to suppress in 2.12, prone to occur in sbt builds) https://github.com/scala/bug/issues/12112

To workaround that sbt now includes

  /** This works around Scala 2.12.12's
   * "a pure expression does nothing in statement position"
   *
   * {{{
   * Def.unit(copyResources.value)
   * Def.unit(compile.value)
   * }}}
   */
  def unit(a: Any): Unit = ()

since https://github.com/sbt/sbt/pull/5743.

If val _ = ... gets backported to 2.12.x that could be the way to go.

SethTisue commented 3 years ago

For scala-library-next, 2.12 doesn't matter. Even 2.13 and 3.0 don't matter. We shouldn't add anything here unless it will be needed in the Scala-3-only world we will eventually be in.

Sciss commented 3 years ago

Doesn't the warning occur only in end-of-block position? I do the following now, which I think is also clear intention when reading the code:


def file: java.io.File

def cleanUp(): Unit = {
  file.delete()
  ()
}
BalmungSan commented 3 years ago

Ok, I just tested in a project (using Scala 2.13.3) where I was using void and it seems that both val _ = ... and (... : Unit) work for silencing both warnings (value discard and unused values). And given that "For scala-library-next, 2.12 doesn't matter", it seems the moment of glory for void would have been the release of 2.13.0.

So, for now, I am closing this.


However, I believe we can take something positive about this and it is that such techniques should be documented somewhere. I think it is fair to say that sbt-tpolecat is somewhat common and even without it -Wvalue-discard is highly recommended on its own. And given that folks that use and recommend such flag (Gavin, Rob and myself to name a few) didn't know about what is probably the best way to deal with it; is, at least, hilarious.

I would like to contribute with such documentation, but I am not sure where would be the best place. But, I believe such a question is a bit off-topic for this issue and this repo in general, so I am moving the discussion to gitter.

Edit

For the record: here are the docs.

SethTisue commented 3 years ago

I am not sure where would be the best place

maybe people will google it and find this ticket :-)

(I am joking, yet also partly serious)

martijnhoekstra commented 3 years ago

To spruce up the potential google juice, maybe those googling for how to fix or suppress the phrase "discarded non-Unit value" will end up here too now that I've added it, and put some potential search phrases next to it.