-
Notifications
You must be signed in to change notification settings - Fork 1.1k
given
initializer with side-effects is not invoked by summon
#19348
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
Comments
In the particular case where a typeclass has inline methods, and no internal state or side-effects, I do like the current behavior of eliding any reference to it in the compiled output. |
Minimisation : object Foo:
println("side-effect")
inline def foo(x : String) = x + "bar"
@main def run =
val foobar = Foo.foo("foo")
println(foobar) if we change |
That still seems intuitively correct to me -- since By contrast, when you're replacing it with a class, you are presumably explicitly instantiating (and thus initializing) the class before calling |
The original reproducer from @armanbilge seems slightly different - the implicit function that creates the |
It's always worked like this.
also compare
|
Are constructs like And how does that compare with the older |
Parameterless So if you need the side effect you should add a dummy type parameter |
I definitely agree! In that case ...
Could parameterless |
I proposed that at some point, but was voted down, since people thought it's not that bad, and better to be safe. But I agree, if we declare side effects to be undefined behavior in givens then we might as well make the lazy val thread-unsafe. However, there a workaround. If the RHS of a parameterless given is a simple immutable reference, the given is implemented as a def. So you can make your value a threadunsafe lazy val (or even strict val), and then forward to it with a given: import annotation.threadUnsafe
class C
object Test:
def foo(): C = C()
@threadUnsafe lazy val _C = foo()
given C = _C If you print the code at erasure phase this is what you get: [[syntax trees at end of erasure]] // test.scala
package <empty> {
@SourceFile("test.scala") class C() extends Object() {}
final lazy module val Test: Test = new Test()
@SourceFile("test.scala") final module class Test() extends Object() {
private def writeReplace(): Object =
new scala.runtime.ModuleSerializationProxy(classOf[Test])
def foo(): C = new C()
@threadUnsafe lazy def _C(): C = Test.foo()
final given def given_C(): C = Test._C()
}
} |
Thanks!
Has anyone benchmarked this? @djspiewak and I were discussing this recently.
It's great that there are workarounds, and in fact we'll probably go straight for |
As far as I know, no benchmarks for this exist far. But it would be great if they did! |
The synchronization of a thread-safe lazy val is not meant to protect the rhs. It protects the reading/writing of the cache (and bitmap) so that we stay within the JMM. Therefore, even side-effect-free rhs'es need synchronization to be correct. |
If I understand you correctly, are you saying that import scala.annotation.threadUnsafe
class Foo {
@threadUnsafe lazy val bar = ???
} decompiles to /*
* Decompiled with CFR 0.151.
*
* Could not load the following classes:
* scala.Predef$
* scala.runtime.Nothing$
*/
import scala.Predef$;
import scala.runtime.Nothing$;
public class Foo {
private Nothing$ bar$lzy1;
private boolean barbitmap$1;
public Nothing$ bar() {
if (!this.barbitmap$1) {
this.bar$lzy1 = Predef$.MODULE$.$qmark$qmark$qmark();
this.barbitmap$1 = true;
}
return this.bar$lzy1;
}
} The problem is that a thread may see that |
Aha, I'm sorry, I take it back. It's not broken, it is "thread unsafe" which is exactly what is promised. |
To expand on my confusion, there are at least three semantics here, from weakest to strongest:
Until now I was quite wrongly under the impression that |
If you want (2) for a specific purpose, you can implement it in user space. I did that to make tasty-query thread-safe: |
Thanks, yes, I've done that before on many occasions. It really comes back to this:
Which is unfortunate, because it seems that |
Uh oh!
There was an error while loading. Please reload this page.
Compiler version
3.4.0-RC1-bin-20231223-938d405-NIGHTLY
Minimized code
Output
Expectation
If we replace
given
withimplicit def foo
:The text was updated successfully, but these errors were encountered: