-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Experimental Streams using quotes #4317
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
Conversation
producer.init(st => '{ | ||
Var('{ (_: Unit) => ()}){ advf => { | ||
Var('{ true }) { hasNext => { | ||
// Var('{ null.asInstanceOf[A] }) { curr => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to generate the following line:
var curr: A = null.asInstanceOf[A]
so I guess the only way is:
Var('{ null.asInstanceOf[A] }) { curr => ...
.
The minimal standalone example that corresponds to the code above is:
trait Bar[T: Type] { def meth(): Unit }
class Foo[T: Type] {
new Bar[T] {
def meth() = {
Var('(null.asInstanceOf[T])) { curr => '() }
}
}
}
The problem is that I get the following error message and I don't know if thats a bug or I am doing something horribly wrong.
25 | new Bar[T] {
| ^^^^^^
| constructor Bar in trait Bar does not take parameters
ping @nicolasstucki
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trait Bar { def meth(): Unit }
class Foo[T: Type] {
new Bar {
def meth() = {
Var('(null.asInstanceOf[T])) { curr => '() }
}
}
}
Var('(null.asInstanceOf[T])) { curr => '() }
| ^
| access to Foo.this from wrong staging level:
| - the definition is at level 0,
| - but the access is at level 1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opened #4350 after investigation
55b5913
to
087a191
Compare
// Fixed: Note to |
@nicolasstucki parallel tests failed. I will restart the build. |
} | ||
|
||
object Stream { | ||
def of[A: Type](arr: Expr[Array[A]]): Stream[A] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try changing it to
def of[A: Type: Liftable](arr0: Array[A]): Stream[A] = {
val arr = arr0.toExpr
...
You will need some lifter for Arrays from the library.
} | ||
|
||
/** A stream containing the first `n` elements of this stream. */ | ||
def take(n: Expr[Int]): Stream[A] = Stream(takeRaw[Expr[A]](n, stream)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def take(n: Int): Stream[A] = Stream(takeRaw[Expr[A]](n.toExpr, stream))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nicolasstucki what’s the advantage of your proposal? At first sight it seems less powerful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The aim is to hide the Expr
from the end user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then do we want fold
to have the following signature?
def fold[W : Type](z: W, f: (W, A) => W): W
I’m not sure this is what we want?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, it is not exactly what I want. We need to hide the Expr behind a macro. I will test my signature idea and then document it here if it works
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should merge like this. It will serve a great regression test. We should refine it further based on this work afterward.
I have the changes you proposed ready but I was stuck in something during the refactoring. I will post here, maybe discuss and merge. Thanks @nicolasstucki |
* {{{ | ||
* /* initialization for stream 1 */ | ||
* | ||
* var curr = null.asInstanceOf[Int] // keeps each element from reified stream |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be 0
instead of null
. Also, it seems that curr
is never updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
I was "updating" it as a comment. Fixing it to illustrate it better!
producer.init(st => | ||
Var('{ (_: Unit) => ()}){ nadv => { | ||
Var('{ true }) { hasNext => { | ||
Var('{ null.asInstanceOf[A] }) { curr => '{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m wondering if this can cause subtle bugs, since null.asInstanceOf[Int]
produces 0
, which is undistinguishable from the value 0
(by contrast with references, where null
can always be distinguished from an object reference).
Why don’t you use Option[A]
instead?
Var(z) { s: Var[W] => '{ | ||
~foldRaw[Expr[A]]((a: Expr[A]) => '{ | ||
~s.update(f(s.get, a)) | ||
}, stream) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any difference between '{ ~s.update(…) }
and s.update(…)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is the same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though I would not change it. This kind of small additions have been useful to find bugs in the implementation. I would keep it like this for as a regression test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However, nice catch @julienrf!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks interesting! Do you have more insights on the generated code or on performance?
} | ||
} | ||
|
||
private def foldRaw[A](consumer: A => Expr[Unit], stream: StagedStream[A]): Expr[Unit] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that we don’t need to take stream
as a parameter since it is already a parameter of the Stream
class. (btw name shadowing is dangerous!)
|
||
def init(k: St => Expr[Unit]): Expr[Unit] = { | ||
producer.init(st => | ||
Var('{ (_: Unit) => ()}){ nadv => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nicolasstucki this is the line that triggers the exception after the last rebase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix in #4592
@biboudis very cool! Has this implementation been benchmarked? Does it expand full stream pipelines into low-level loops, as in the paper? |
Thanks @LPTK. Yes, by inspection, the code generates the expected imperative low-level loops. If needed we will benchmark it in the future. For now this is merely a big test case for us. |
Port of the strymonas library as described in O. Kiselyov et al., Stream fusion, to completeness (POPL 2017) using Dotty's staging facility.
Ideas: