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
Stream.cons result not thread-safe #1220
Comments
Imported From: https://issues.scala-lang.org/browse/SI-1220?orig=1
|
@DRMacIver said: |
@richdougherty said:
That's a good idea in theory. The trouble is that the Stream needs to be aware of whether or not the tail has been evaluated (see hasDefiniteSize, addDefinedElems). I don't think it's possible to find that out when using the 'lazy' keyword. Or am I wrong in making this assumption? |
@DRMacIver said: var thunked = false;
lazy val foo = {thunked = true; fooCalc } It would be nice if you could access the functionality to determine if the value had been thunked without needing to recreate it yourself though. |
@paulp said:
You're wasting a perfectly good bit there, bub! scala> class Foo { lazy val bar = 5 } defined class Foo
scala> val x = new Foo
x: Foo = Foo@c7f3e3
scala> val f = x.getClass.getField("bitmap$$0")
f: java.lang.reflect.Field = public volatile int Foo.bitmap$$0
scala> def isEvaluated = (f.getInt(x) & 1) != 0
isEvaluated: Boolean
scala> isEvaluated
res0: Boolean = false
scala> x.bar
res2: Int = 5
scala> isEvaluated
res3: Boolean = true Which is not to say this approach doesn't have a certain fragility and oh so slight implementation dependence... but I see no reason there couldn't be an interface to the data. |
@oschulz said: |
@oschulz said: I've appended a patch with a proposed solution (passes It replaces Stream.Cons by @serializable @SerialVersionUID(2734764611255889683L)
final class Cons[+A](hd: A, tl: => Stream[A]) extends Stream[A] {
override def isEmpty = false
override val head = hd
def tailDefined = tailDefinedVar
@volatile private var tailDefinedVar = false
override lazy val tail: Stream[A] = {
tailDefinedVar = true
tl
}
} I regenerated the serial version UID, since this will be incompatible with the old one, right? |
@oschulz said: |
The Stream object returned by cons evaluates its tail lazily, then caches the result in a member variable. Unfortunately, this evaluation can happen more than once if tail is called from multiple threads. If the tail function has state, then this can cause invalid results.
I think this behaviour should either be fixed - by synchronizing when evaluating/inspecting the tail - or documented somewhere. I've attached a script that demonstrates the problem and a rough solution.
The text was updated successfully, but these errors were encountered: