-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Introduce Unit.void[A](x: A): Unit #7530
Conversation
This is useful when you want to explicitly discard a value, without having to val it and force your expression to be a block. Ideally this would be defined on the Unit type rather than the Unit companion object, but I couldn't figure out the backend changes necessary to get it to handle that...
What is wrong with |
I'd prefer having a method, and not need a block. The best way is having it as a method on Any (like toUnit), which we can do if it's preferred. |
This proposal will run afoul of disallowing references to Unit companion because folks confuse it with the unit value. I already made a similar joke, but actually why not co-opt asInstanceOf. |
I agree Unit should be its own companion object, rather than have one. But I'm ignoring that for now and just doing what's easier to implement.
If you mean co-opt in the standard library, then co-opt away. But in user-land I'd like a function somewhere. |
I forgot another good reason, @Ichoran: to make it explicit that you're discarding a value. Obviously, your example is pretty obvious (and made me forget), but it would be nice to have the option of being explicit. Also: that doesn't work for the use case that I noticed in a project that has a local version of this: class StringContextOps private[skunk](sc: StringContext) {
void(sc)
def sql(argSeq: Any*): Any =
macro StringContextOps.StringOpsMacros.sql_impl
def id(): Identifier =
macro StringContextOps.StringOpsMacros.identifier_impl
} |
The explicit version is The joke on the other ticket was to use |
@dwijnand - What is the advantage of a method here over a block? It's just another way to do things. It's not like (Also, I don't know what |
The advantage is it's a function, which has a name. It's not just a jumble of symbols (2 brackets, 2 parens and a semicolon). It's an express decision to transform a value to unit.
I disagree. (Unless you mean "void isn't documented", in that case, fair point) |
Well, I guess you could've done that. But I didn't even think you could, because I'm already in a block (the class constructor). In retrospect it's obvious. But it would also be unnecessary if we just had... a function available in the standard library that allowed me to discard a value, without having to do the secret symbol dance of |
Actually [error] /d/skunk/modules/core/src/main/scala/syntax/StringContextOps.scala:13:5: a pure expression does nothing in statement position
[error] { sc; () }
[error] ^
[error] one error found so then you try [error] /d/skunk/modules/core/src/main/scala/syntax/StringContextOps.scala:13:3: a pure expression does nothing in statement position; multiline expressions may require enclosing parentheses
[error] { val _ = sc; () }
[error] ^ So then you just go back to using (and therefore locally defining) |
|
@dwijnand - I mean if I see
In contrast, The only method name that might possibly have this property which isn't a full sentence is Also, with your example, why does either |
Unit.eval?
--
Cheers,
√
|
How about a type alias `type Unused = Unit @unchecked`? And then `sc():
Unused`
…On Sat, Dec 15, 2018 at 11:01 kerr ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In test/junit/scala/UnitTest.scala
<#7530 (comment)>:
> @@ -0,0 +1,8 @@
+package scala
+
+import org.junit.Assert._
+import org.junit.Test
+
+final class UnitTest {
not test no unused warning too
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#7530 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAFjy4m-EA0NKOesOHJKTnCLMD18xIhXks5u5MiIgaJpZM4ZT8rj>
.
|
I don't think these are strong arguments. It's hard to prove intuition and friendliness I think. I think it's partially based on what you know. Clearly, you don't know
You're right, and I'm looking for ideas:
Asides from not everything is an expression (there are also imports and definitions, TIL, SLS 6.25), everything is an expression but also we discard non-unit values and insert units in its place (which sometimes means no bytecode, sometimes means boxed unit).
Again, here it's clear to you what's happened because of what you know. To someone else it might not be clear what's happening to that value replace returned. (just for the sake of argument, one could go on and say the dot notation is unclear, the semi-colon is unclear, it's all relative and therefore a difficult argument to stand on IMHO)
I don't hate
According to that compilation unit that |
Interesting idea! But it doesn't work 😕 [error] /d/skunk/modules/core/src/main/scala/syntax/StringContextOps.scala:15:3: type mismatch;
[error] found : StringContext
[error] required: StringContextOps.this.Unused
[error] (which expands to) Unit @unchecked
[error] sc: Unused
[error] ^ |
Scrap the eval name—the thinking was that it takes an expression and makes
it evaluate to Unit.
Another idea is to call it ”of” so: Unit.of(expr) or have a toUnit on
Any.
--
Cheers,
√
|
Don't mind Why toUnit on AnyVal? Assuming you mean AnyVal type and that uses |
@dwijnand Sorry, meant Any! :) |
But we have the means to make it work! ;-)
…On Sat, Dec 15, 2018 at 20:49 Viktor Klang (√) ***@***.***> wrote:
@dwijnand <https://github.com/dwijnand> Sorry, meant Any! :)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#7530 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAFjyyfbb9MNr-G18Ilk3QQ2L3M3O0WZks5u5VJigaJpZM4ZT8rj>
.
|
True. Now I don't hate the idea, but why do you propose it over a method? For instance, as a comparison, why do |
Shouldn't deprecate the const and introduce identity? I think Function.ignore will be good. |
We could add an In all seriousness, |
Respectfully, I think that with the goals in mind of:
I would prefer to this not be added. I think that when you want to explicitly discard an expression Maybe if I saw some really nasty examples where having to do this hurts readability, I could be convinced though. |
I agree. I think ”; ()” is enough. That said, the discoverability is
suffering, so how about adding it to the compiler error message when Unit
is expected but something else is provided?
--
Cheers,
√
|
The last object Function {
type Ignored = Unit
def ignore[T](t: T): Ignored = {
val _ = t
}
} |
True, the compiler can insert that unit for you. |
Note that as of recently you can use the underscore trick multiple times in scope. M5 errors with multiple defs, which was one motivation for a macro that silently consumes a value.
Maybe the |
IIUC simple type ascription should solve the problem: // all constructs below compile fine under Scala 2.12.1
5: Unit
"dfs": Unit
(5 + 5): Unit
Option(5: Unit) |
I saw two examples in this thread. One is with unused constructor parameter. We can turn it into private val, so it will always be a field in the bytecode. Another one is about changing return type to Unit. Instead of doing WDYT? |
I prefer a type ascription because you’re communicating with the type
checker/linter, not the runtime.
…On Sun, Dec 16, 2018 at 18:29 Piotr Tarsa ***@***.***> wrote:
I saw two examples in this thread.
One is with unused constructor parameter. We can turn it into private val,
so it will always be a field in the bytecode.
Another one is about changing return type to Unit. Instead of doing { val
_ = m.replace(k, v) } we can do m.replace(k, v): Unit.
WDYT?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#7530 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAFjywGTOjhAloWXi35iM1TfLGZYeNP0ks5u5oMSgaJpZM4ZT8rj>
.
|
I'd be fine with that, provided we can implement that in time... |
'ignore' is the name i use for this function |
This PR LGTM in its current form. Other alternatives work as well. |
What about: object Unit {
def cast(ignored: Unit): Unit = ()
} ? |
@tarsa That doesn't work because the value would be ignored at the call-site, which is part of the whole point of this. Also I encourage you to try your ideas in the |
If we're going to do this, ergonomically it would usually be more convenient as
|
I'd be happy to provide that, ala Perhaps |
for reference on what is considered discarding a value: scala> def foo(x: String): Unit = { x.length; () }
foo: (x: String)Unit
scala> def foo(x: String): Unit = { val _ = x.length }
foo: (x: String)Unit
scala> def foo(x: String): Unit = { x.length }
<console>:11: warning: discarded non-Unit value
def foo(x: String): Unit = { x.length }
^
foo: (x: String)Unit |
You can't express those with a type ascription, and they actually have a run time component (i.e., you want to evaluate the function). In this case, we're just communicating intent / silencing warnings. I'm not in favor of adding a method for this. |
I think just like I'd actually be fine with your idea, it's just harder to implement and I don't know if I have the chops to do it in time... |
I don’t think my approach needs to land in 2.13.0. We can do a hangout and
pair program it tomorrow if you like, or next year :-)
…On Thu, 20 Dec 2018 at 18:38, Dale Wijnand ***@***.***> wrote:
I think just like () is a type, but doesn't have a runtime component, A
=> () is a perfectly valid function, so I don't see why it should be
shunned from the standard library. Fair enough it can be elided from the
bytecode like () is.
I'd actually be fine with your idea, it's just harder to implement and I
don't know if I have the chops to do it in time...
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#7530 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAFjy_rEU_792IvUonrV4Z1_RLwWkNiMks5u68sKgaJpZM4ZT8rj>
.
|
Closed in favour of #7560. |
This is useful when you want to explicitly discard a value, without
having to val it and force your expression to be a block.
Ideally, this would be defined on the Unit type rather than the Unit
companion object, but I couldn't figure out the backend changes
necessary to get it to handle that...
Possible alternative names: discard, drop, forget, unit, ...
TODO:
Review (and help wanted) by @lrytz or @adriaanm, kindly.