5

Wrote this code

scala> import scala.collection.immutable.{Stream => _}
scala> Stream(1, 2, 3)
res0: scala.collection.immutable.Stream[Int] = Stream(1, ?)

But shouldn't the second line fail? because I hid the Stream class from import in line 1? why is it still visible?

I also tried

scala> import scala.collection.immutable.{Stream => DoNotUse}
import scala.collection.immutable.{Stream=>DoNotUse}

scala> Stream(1, 2, 3)
res1: scala.collection.immutable.Stream[Int] = Stream(1, ?)

Again, this is still visible.

Knows Not Much
  • 30,395
  • 60
  • 197
  • 373
  • 7
    You can't unimport it through `scala.collection.immutable`, because it's built-in as type alias right into the top level [scala](https://www.scala-lang.org/api/current/scala/index.html#Stream[+A]=scala.collection.immutable.Stream[A]) package. What are you trying to achieve, exactly? – Andrey Tyukin Jan 10 '19 at 17:34
  • I want to default to fs2.Stream. I never want to see scala.collection.immutable.Stream. – Knows Not Much Jan 10 '19 at 17:35
  • 1
    I think, if you just `import fs2.Stream` it'll hide the default one – Dima Jan 10 '19 at 17:38
  • 1
    only if fs2.Stream import is the last. Also, it should still be possible to hide the default implementation of Stream. – Knows Not Much Jan 10 '19 at 17:42
  • 3
    Well, theoretically, there is [`-Yno-imports`](https://docs.scala-lang.org/overviews/compiler-options/index.html#Private_Settings)... But I'm pretty sure that it's not worth it for those four characters (`fs2.`). – Andrey Tyukin Jan 10 '19 at 17:50
  • 1
    Stream is deprecated in 2.13. It would be handy to have an option that the root imports never import deprecated stuff. I'll create a ticket! – som-snytt Jan 10 '19 at 21:04
  • I created that ticket, apparently, and also someone else had already created a ticket for this question at https://github.com/scala/bug/issues/11317 – som-snytt Dec 18 '19 at 20:48

3 Answers3

2

Here's an example with the new -Yimports in 2.13.

$ cat S.scala

package mystream

class Stream[A]

object MyPredef {
  type Stream[A] = mystream.Stream[A]
}

Imports later in the list shadow earlier ones:

$ scala -Yimports:java.lang,scala,scala.Predef,mystream.MyPredef
Welcome to Scala 2.13.0 (OpenJDK 64-Bit Server VM 11.0.1)

scala> new Stream[Int]
res0: mystream.Stream[Int] = mystream.Stream@65fe2691

It's not as convenient as the hypothetical syntax

-Yimports:java.lang._,scala.{Stream=>_, _},scala.Predef._

which would support your use case more directly.

Alternatively, it's usual to put aliases in an enclosing package object:

package object mystuff {
  type Stream[A] = mystream.Stream[A]
}

and

scala> :pa
// Entering paste mode (ctrl-D to finish)

package mystuff {
  class C { def f = new Stream[Int] }
}

// Exiting paste mode, now interpreting.


scala> new mystuff.C().f
res1: mystream.Stream[Int] = mystream.Stream@715fa8c5

but the alias is scoped to those subpackages and not any compilation unit.

som-snytt
  • 39,429
  • 2
  • 47
  • 129
0

In Scala, you can use some default types without import. All these types are located in package scala._. For example List, Throwable etc.

scala.collection.immutable.Stream has alias in this package: https://github.com/scala/scala/blob/2.13.x/src/library/scala/package.scala#L86

  • 3
    OK, so how does this answer the question? If you are trying to say that `immutable.Stream` **cannot** be blocked, and it is impossible to guarantee no accidental usage, then say so. – jwvh Jan 11 '19 at 18:45
-1

You can't "unimport" an imported value. If you write import scala.collection.immutable.{Stream => _}, you will just add another import to your namespace.


Here's another example:

import scala.collection.immutable.{Stream => Foo}
import scala.collection.immutable.{Stream => Bar}

The second line does not remove the first import. Both lines just add one additional import to your namespace. You can now refer to Stream as Foo and Bar.


Why do you wan't to remove an import? If you don't want to use the class, just don't use it. There's no need to remove an import. It does not add a dependency on Stream or any other drawback at runtime, imports are a compiletime only concept.

Maybe you have your own class named Stream that you want to use. Therefore it is not necessary it "remove" the default Stream import. Just import your class. This will shadow the default import.

import foo.Stream
val x: Stream[_] = ??? // this variable has type `foo.Stream`

// Here we have another import of a class with the same name.
// This shadows the first import, so any occurence of `Stream`
// does from now on refer to `bar.Stream`.
import bar.Stream
val x: Stream[_] = ??? // This variable has type `bar.Stream`
Aki
  • 1,644
  • 12
  • 24
  • The reason to remove the standard alias from scope is to avoid accidental usage, as well as improve autocompletion in tooling. Accidental usage can be subtle in ways you might not notice, for example, a replacement `Set` with a stricter `contains` signature. – som-snytt Jan 10 '19 at 21:01