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

value Stream in package scala is deprecated (since 2.13.0) #1066

Closed
jimka2001 opened this issue Aug 1, 2024 · 11 comments
Closed

value Stream in package scala is deprecated (since 2.13.0) #1066

jimka2001 opened this issue Aug 1, 2024 · 11 comments

Comments

@jimka2001
Copy link

I'm getting deprecation warnings when I compile my project:

[warn]       SEmpty #:: STop #:: Stream.empty
[warn]                       ^
[warn] /Users/jimka/Repos/rte/scala-rte/src/test/scala/genus/GenusSpecifications.scala:126:34: object Stream in package immutable is deprecated (since 2.13.0): Use LazyList (which is fully lazy) instead of Stream (which has a lazy tail only)
[warn]       SEmpty #:: STop #:: Stream.empty
[warn]                                  ^
[warn] /Users/jimka/Repos/rte/scala-rte/src/test/scala/genus/GenusSpecifications.scala:126:27: value Stream in package scala is deprecated (since 2.13.0): Use LazyList instead of Stream
[warn]       SEmpty #:: STop #:: Stream.empty
[warn]                           ^
[warn] /Users/jimka/Repos/rte/scala-rte/src/test/scala/genus/GenusSpecifications.scala:129:7: value Stream in package scala is deprecated (since 2.13.0): Use LazyList instead of Stream
[warn]       Stream.empty
[warn]       ^

I believe this is caused by the declaration of Shrink which seems to be the following

sealed abstract class Shrink[T] extends Serializable {
  def shrink(x: T): Stream[T]

  /** Create a new shrink that only produces values satisfying the given condition.
   */
  def suchThat(f: T => Boolean): Shrink[T] = Shrink(v => this.shrink(v).filter(f))
}

If I change my use of Stream.empty to LazyList.empty, then I get the following compilation error.

/Users/jimka/Repos/rte/scala-rte/src/test/scala/genus/GenusSpecifications.scala:94:37
type mismatch;
 found   : scala.collection.immutable.LazyList[genus.SimpleTypeD]
 required: Stream[genus.SimpleTypeD]
      if (t.tds.size == 1) t.tds(0) #:: s else {
@SethTisue
Copy link
Member

SethTisue commented Aug 1, 2024

(I haven't studied this myself but) as someone pointed out on Discord, #627 seems relevant here

@jimka2001
Copy link
Author

When I look at #627 I don't really understand the discussion, but it seems SethTisue merged a fix for this in Feb 2020. #627 (review)

Was this a different issue that just looks similar?

@SethTisue
Copy link
Member

@jimka2001 it might help if you showed a little more of the context in your code – the context in which you wrote SEmpty #:: STop #:: Stream.empty

@jimka2001
Copy link
Author

jimka2001 commented Aug 1, 2024

Here is a permalink to the function in question; not sure if there are other similar functions
https://github.com/jimka2001/scala-rte/blob/7150fb784a18676b80eebdd7dd4928a7fc5bcf5c/src/test/scala/genus/GenusSpecifications.scala#L89

here is the content of the function


  //  Shrinks according to the following strategy
  //    - Try STop and SEmpty
  //    - Try removing 1 different child at each iteration
  //    - Try to shrink 1 different child at each iteration
  //    - If a SCombination only has 1 child, try with the child
  // Implementation similar to this Ast Shrinker (https://stackoverflow.com/questions/42581883/scalacheck-shrink)
  implicit def shrinkGenus: Shrink[genus.SimpleTypeD] = Shrink {
    case t: SCombination =>
      var s: Stream[SimpleTypeD] = SEmpty #:: STop #:: Stream.empty

      // If 1 child and is TerminalType, put the child in stream
      if (t.tds.size == 1) t.tds(0) #:: s else {

        // Append to the stream the SimpleTypeD with 1 child removed at each iteration
        for {
          i <- 0 until t.tds.size
        } s = t.create(t.tds.take(i) ++ t.tds.drop(i + 1)) #:: s

        // Append to the stream the SimpleTypeD with 1 child shrunk at each iteration
        for {
          i <- 0 until t.tds.size
        } s = shrink(t.tds(i)).map(e => t.create(t.tds.take(i) ++ t.tds.drop(i + 1).appended(e))) #::: s

        s
      }

    // Try STop, SEmpty, or the child
    case t: SNot =>
      SEmpty #:: STop #:: t.s #:: Stream.Empty

    // Try STop, SEmpty, or shrink the content
    case t: SEql =>
      SEmpty #:: STop #:: shrink(t.a).map(SEql(_))

    // Try STop, SEmpty, or shrink the content
    case t: SMember =>
      SEmpty #:: STop #:: SMember(shrink(t.xs)) #:: Stream.empty

    // Try STop, SEmpty, or shrink the content
    case t: SSatisfies =>
      SEmpty #:: STop #:: shrink(t.f).map(SSatisfies(_, t.printable))

    case t: SAtomic =>
      SEmpty #:: STop #:: Stream.empty

    case t =>
      Stream.empty
  }

@SethTisue
Copy link
Member

I would expect it to work if you expunge all use of Stream and use LazyList everywhere.

Try that. If it doesn't work, show the version of the code that uses only LazyList.

@satorg
Copy link
Contributor

satorg commented Aug 1, 2024

@jimka2001 , according to the snippet, you're trying to make use of the original Shrink.apply method, which relies on Stream. What you're probably looking for is a newer Shrink.withLazyList constructor. It takes T => LazyList[T] instead and converts LazyList to Stream under the hood.

@jimka2001
Copy link
Author

@SethTisue are you suggesting I change the return type of implicit def shrinkGenus so that it returns LazyList[genus.SimpleTypeD] rather than Shrink[genus.SimpleTypeD]?

@jimka2001
Copy link
Author

jimka2001 commented Aug 2, 2024

I would expect it to work if you expunge all use of Stream and use LazyList everywhere.

Try that. If it doesn't work, show the version of the code that uses only LazyList.

I'm not sure if I understand the suggestion. Here is a version of the code which uses only LazyList.
https://github.com/jimka2001/scala-rte/blob/b44894bc9c7f49b034a1bf1796c08b7e11b67f88/src/test/scala/genus/GenusSpecifications.scala#L92

If I understand correctly, shrink returns a Stream, so every time I call shrink I must convert the value back to LazyList. i'm doing this with the oneline function lshrink defined like this:

  // Defining this method temporarily to help debug a compiler error or deprecation warning.
  def lshrink[A](a:A):LazyList[A] = shrink(a).to(LazyList)

This version does not compile.

/Users/jimka/Repos/rte/scala-rte/src/test/scala/genus/GenusSpecifications.scala:91:64
missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: ? => Stream[?]
  implicit def shrinkGenus: Stream[genus.SimpleTypeD] = Shrink {

If I change shrinkGenus to return LazyList[genus.SimpleTypeD], https://github.com/jimka2001/scala-rte/blob/31e6ff104577fd010d2de67a9b91a084504e17a7/src/test/scala/genus/GenusSpecifications.scala#L92, then
I get what looks like the same compilation error.

/Users/jimka/Repos/rte/scala-rte/src/test/scala/genus/GenusSpecifications.scala:92:66
missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: ? => Stream[?]
  implicit def shrinkGenus: LazyList[genus.SimpleTypeD] = Shrink {

@jimka2001
Copy link
Author

OK, I finally got it to work by removing the call to Shrink.

The code now compiles, and at least the local tests pass, i.e. the tests for this package.

Perhaps that should have been obvious, but I didn't realize Shrink was a constructor, I thought it was just a function that needed to be called to make the tester shrink the data. I also had to add a patter matching call.
https://github.com/jimka2001/scala-rte/blob/63535dfd7eab6357a66422f2cd30ea2839c7272a/src/test/scala/genus/GenusSpecifications.scala#L94


  // Implementation similar to this Ast Shrinker (https://stackoverflow.com/questions/42581883/scalacheck-shrink)
  implicit def shrinkGenus(td:SimpleTypeD): LazyList[SimpleTypeD] = td match {
    case t: SCombination =>
      var s: LazyList[SimpleTypeD] = SEmpty #:: STop #:: LazyList.empty

      // If 1 child and is TerminalType, put the child in stream
      if (t.tds.size == 1) t.tds(0) #:: s else {

        // Append to the stream the SimpleTypeD with 1 child removed at each iteration
        for {
          i <- 0 until t.tds.size
        } s = t.create(t.tds.take(i) ++ t.tds.drop(i + 1)) #:: s

        // Append to the stream the SimpleTypeD with 1 child shrunk at each iteration
        for {
          i <- 0 until t.tds.size
        } s = lshrink(t.tds(i)).map(e => t.create(t.tds.take(i) ++ t.tds.drop(i + 1).appended(e))) #::: s

        s
      }

    // Try STop, SEmpty, or the child
    case t: SNot =>
      SEmpty #:: STop #:: t.s #:: LazyList.empty

    // Try STop, SEmpty, or shrink the content
    case t: SEql =>
      SEmpty #:: STop #:: lshrink(t.a).map(SEql(_))

    // Try STop, SEmpty, or shrink the content
    case t: SMember =>
      SEmpty #:: STop #:: SMember(lshrink(t.xs)) #:: LazyList.empty

    // Try STop, SEmpty, or shrink the content
    case t: SSatisfies =>
      SEmpty #:: STop #:: lshrink(t.f).map(SSatisfies(_, t.printable))

    case t: SAtomic =>
      SEmpty #:: STop #:: LazyList.empty

    case _ =>
      LazyList.empty
  }
}

@SethTisue SethTisue closed this as not planned Won't fix, can't repro, duplicate, stale Aug 2, 2024
@SethTisue
Copy link
Member

thanks for providing the fixed code, perhaps it will help someone else in a similar situation

@satorg
Copy link
Contributor

satorg commented Aug 2, 2024

@SethTisue @jimka2001 , just for a record:

If you simply provide an implicit conversion for type A like that:

implicit def shrinkA(a: A): LazyList[A] = ???

that implicit conversion won't be used for shrinking per sei, and the default shrinking will be used instead, i.e. this one:

trait ShrinkLowPriority {
/** Default shrink instance */
implicit def shrinkAny[T]: Shrink[T] = Shrink(_ => Stream.empty)
}

which means no shrinking.

If you need a custom shrinking for type A, you still have to provide an implicit Shrink[A] instance for that.

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

3 participants