Skip to content
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#iterator should be override. #3273

Closed
scabug opened this issue Apr 9, 2010 · 12 comments
Closed

Stream#iterator should be override. #3273

scabug opened this issue Apr 9, 2010 · 12 comments
Assignees

Comments

@scabug
Copy link

scabug commented Apr 9, 2010

/*My English is not so good, forgive my expression */
The iterator method of Stream is defined in LinearSeqLike now. I think it should be override in class Stream to make it more lazy.
In my opinion, it should be something like following:

class Stream[A] {
   ...
  class LazyCell[T](st: => Stream[T]){ lazy val v = st }
  
  def iterator: Iterator[A] = new Iterator[A] {
    var these = new LazyCell(Stream.this)
    def hasNext: Boolean = !these.v.isEmpty
    def next: A = 
      if (hasNext) {
        val result = these.v.head; 
        these =new LazyCell(these.v.tail); 
	result
      } else Iterator.empty.next
    override def toList: List[A] = stream.toList
  }
}
@scabug
Copy link
Author

scabug commented Apr 9, 2010

Imported From: https://issues.scala-lang.org/browse/SI-3273?orig=1
Reporter: Eastsun (eastsun)

@scabug
Copy link
Author

scabug commented Apr 9, 2010

Eastsun (eastsun) said:
I discovered this ticket during the time when I try to fix #2634.
I have spend a couple of hours try to find why my solution which mentioned in #3265 didn't work. It confused my very much. I still don't know the reason, but I find something interested.
In the following code, we can only get a StackOverflowError if using
{code}
val fib: Stream[Int] = 1 #:: 1 #:: (fib, fib.tail).zippedx2.map(_ + _)
{code}.
We can get fib(2) and a StackOverflowError if using

val fib: Stream[Int] = 1 #:: 1 #:: (fib, fib.tail).zippedx.map(_ + _)

While I expected to get fib(3) without any exception. I must have something missed. Is there any one to tell me why. I believe it is the key to fix #3273

import scala.collection.{TraversableLike, IterableLike}
import scala.collection.generic.CanBuildFrom

class LazyItrSt[A](stream: Stream[A]) {

  class LazyCell[T](st: => Stream[T]){ lazy val v = st }
  
  def iterator: Iterator[A] = new Iterator[A] {
    var these = new LazyCell(stream)
    def hasNext: Boolean = !these.v.isEmpty
    def next: A = 
      if (hasNext) {
        val result = these.v.head; 
		these =new LazyCell(these.v.tail); 
		result
      } else Iterator.empty.next
    override def toList: List[A] = stream.toList
  }
}

class Zippedx[+Repr1, +El1, +Repr2, +El2](coll1: TraversableLike[El1, Repr1], coll2: IterableLike[El2, Repr2]) { 
    def map[B, To](f: (El1, El2) => B)(implicit cbf: CanBuildFrom[Repr1, B, To]): To = {
      val elems2 = (new LazyItrSt(coll2.asInstanceOf[Stream[El2]])).iterator

      for(el1 <- coll1 if elems2.hasNext) yield f(el1, elems2.next)
    }
}

class Zippedx2[+Repr1, +El1, +Repr2, +El2](coll1: TraversableLike[El1, Repr1], coll2: IterableLike[El2, Repr2]) { 
    def map[B, To](f: (El1, El2) => B)(implicit cbf: CanBuildFrom[Repr1, B, To]): To = {
      val elems2 = coll2.iterator

      for(el1 <- coll1 if elems2.hasNext) yield f(el1, elems2.next)
    }
}

object Debug extends Application {
    implicit def t2t[T1,T2](t: (T1,T2)) = new {
        def zippedx[Repr1, El1, Repr2, El2](implicit w1: T1 => TraversableLike[El1, Repr1],
                                                  w2: T2 => IterableLike[El2, Repr2]): Zippedx[Repr1, El1, Repr2, El2]
            = new Zippedx[Repr1, El1, Repr2, El2](t._1, t._2)
    }
	
	implicit def t2t2[T1,T2](t: (T1,T2)) = new {
        def zippedx2[Repr1, El1, Repr2, El2](implicit w1: T1 => TraversableLike[El1, Repr1],
                                                  w2: T2 => IterableLike[El2, Repr2]): Zippedx2[Repr1, El1, Repr2, El2]
            = new Zippedx2[Repr1, El1, Repr2, El2](t._1, t._2)
    }
	val fib: Stream[Int] = 1 #:: 1 #:: (fib, fib.tail).zippedx2.map(_ + _)
        //val fib: Stream[Int] = 1 #:: 1 #:: (fib, fib.tail).zippedx.map(_ + _)
	println(fib(2))
	println(fib(3))
}
  




 
  
  

@scabug
Copy link
Author

scabug commented Apr 9, 2010

Eastsun (eastsun) said:
"I believe it is the key to fix SI-3273“ => "I believe it is the key to fix SI-2634"

@scabug
Copy link
Author

scabug commented Apr 9, 2010

Eastsun (eastsun) said:
Haha, I finaly find the reason !!!
The implementation of Stream#iterator is wrong which I showed above.
There is the correct one:

class Stream[A] {
   ...
  class LazyCell[T](st: => Stream[T]){ lazy val v = st }
  
  def iterator: Iterator[A] = new Iterator[A] {
    var these = new LazyCell(Stream.this)
    def hasNext: Boolean = !these.v.isEmpty
    def next: A = 
        if (hasNext) {
            val result = these.v.head
            val tmp = these      //Here...
            these =new LazyCell(tmp.v.tail); 
	    result
        } else Iterator.empty.next
    override def toList: List[A] = Stream.this.toList
  }
}

@scabug
Copy link
Author

scabug commented Apr 11, 2010

@paulp said:
Replying to [comment:4 Eastsun]:

Haha, I finaly find the reason !!!
The implementation of Stream#iterator is wrong which I showed above.
There is the correct one:

I applaud your progress, but so far in my limited fiddling with your implementation I haven't gotten zipped to behave fully lazily. I can't spend any more time on it, but it would be great if you could take this all the way to a patch against trunk. (I can't guarantee it'll go into 2.8 though.)

@scabug
Copy link
Author

scabug commented Apr 12, 2010

Eastsun (eastsun) said:
Replying to [comment:5 extempore]:

I applaud your progress, but so far in my limited fiddling with your implementation I haven't gotten zipped to behave fully lazily. I can't spend any more time on it, but it would be great if you could take this all the way to a patch against trunk. (I can't guarantee it'll go into 2.8 though.)

It works fine in my tests.
However, I don't satisfied with this way to fix #2634 since it is not perfect at all(as I mentioned in [http://old.nabble.com/Some-ideas-of-lazy-version-takeWhile-method-in-TraversableLike.-td28189940.html]).
In my opinion, just keep the status of #2634 until we have a pefect solution.

Anyway, this ticket(SI-3273) should be fixed

  override /*LinearSeqLike*/ 
  def iterator: Iterator[A] = new Iterator[A] {
  
    class LazyCell(st: => Stream[A]){ lazy val v = st }
    
    var these = new LazyCell(self)
    def hasNext: Boolean = !these.v.isEmpty
    def next: A = 
      if (hasNext) {
        val cur = these.v
        val result = cur.head
        these = new LazyCell(cur.tail)
        result
      } else Iterator.empty.next
    override def toStream: Stream[A] = these.v
    override def toList: List[A] = these.v.toList
    
  }

@scabug
Copy link
Author

scabug commented Apr 28, 2010

@dubochet said:
Paul, can you please follow up on this issue, and close the ticket if you are happy with the patch or think the discussion is exhausted, or forward it to scala_meeting if you need additional input from Martin or other people.

@scabug
Copy link
Author

scabug commented Sep 14, 2010

@SethTisue said:
this discussion is difficult to follow. Eastsun proposes a fix, but what bug does it fix? I'm not clear on why this is a separate ticket from #2634.

is there something short I can type into the REPL to see for myself that Stream.iterator needs to be "more lazy"?

@scabug
Copy link
Author

scabug commented Sep 14, 2010

Eastsun (eastsun) said:
Replying to [comment:9 SethTisue]:

this discussion is difficult to follow. Eastsun proposes a fix, but what bug does it fix? I'm not clear on why this is a separate ticket from #2634.

is there something short I can type into the REPL to see for myself that Stream.iterator needs to be "more lazy"?

scala> val num1: Stream[Int] = 1 #:: num1.map{ _+1 }
num1: Stream[Int] = Stream(1, ?)

scala> num1.take(10).toList
res1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> val num2: Stream[Int] = 1 #:: num2.iterator.map{ _+1 }.toStream
num2: Stream[Int] = Stream(1, ?)

scala> num2.take(10).toList
java.lang.StackOverflowError
        at scala.collection.LinearSeqLike$$$$anon$$1.hasNext(LinearSeqLike.scala:54)
        at scala.collection.Iterator$$$$anon$$19.hasNext(Iterator.scala:368)
        at scala.collection.Iterator$$class.toStream(Iterator.scala:1011)
        at scala.collection.Iterator$$$$anon$$19.toStream(Iterator.scala:367)
        at $$anonfun$$1.apply(<console>:5)
        at $$anonfun$$1.apply(<console>:5)
        at scala.collection.immutable.Stream$$Cons.tail(Stream.scala:571)
        at scala.collection.immutable.Stream$$Cons.tail(Stream.scala:565)
        at scala.collection.LinearSeqLike$$$$anon$$1.next(LinearSeqLike.scala:57)
        at scala.collection.Iterator$$$$anon$$19.next(Iterator.scala:369)
        at scala.collection.Iterator$$class.toStream(Iterator.scala:1011)
        at scala.collection.Iterator$$$$anon$$19.toStream(Iterator.scala:367)
        at $$anonfun$$1.apply(<...

And with lazy iterator:

scala> def lazyItr[A](xs: Stream[A]): Iterator[A] = new Iterator[A] {
     |
     |     class LazyCell(st: => Stream[A]){ lazy val v = st }
     |
     |     var these = new LazyCell(xs)
     |     def hasNext: Boolean = !these.v.isEmpty
     |     def next: A =
     |       if (hasNext) {
     |         val cur = these.v
     |         val result = cur.head
     |         these = new LazyCell(cur.tail)
     |         result
     |       } else Iterator.empty.next
     | }
lazyItr: [A](xs: Stream[A])Iterator[A]

scala> val num3: Stream[Int] = 1 #:: lazyItr(num3).map{ _+1 }.toStream
num1: Stream[Int] = Stream(1, ?)

scala> num3.take(10).toList
res0: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

@scabug
Copy link
Author

scabug commented Sep 15, 2010

@paulp said:
(In r22995) Stream gets a specialized, extra-lazy Iterator so it can iterate
as lazily as it traverses. Patch submitted by "Eastsun": probably
not his real name, but that's what we call him. Closes #3273,
review by prokopec.

@scabug
Copy link
Author

scabug commented Sep 16, 2010

Eastsun (eastsun) said:
Is there anyone interested in #3526 ?
I think it's time to fix it.
BTW: My name is Xudong Sun(In Chinese,xudong means the sun in the morning :)), I am in China.

@scabug
Copy link
Author

scabug commented Sep 16, 2010

@paulp said:
Replying to [comment:12 Eastsun]:

Is there anyone interested in #3526 ?
I think it's time to fix it.
BTW: My name is Xudong Sun(In Chinese,xudong means the sun in the morning :)), I am in China.

In case you're not on the list, see my comments at http://permalink.gmane.org/gmane.comp.lang.scala.internals/3890 . (Further discussion at #3526 please.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants