3

I setup a Scala project and add this snippet from http://www.scalatest.org/

import collection.mutable.Stack
import org.scalatest._

class ExampleSpec extends FlatSpec with Matchers {

  "A Stack" should "pop values in last-in-first-out order" in {
    val stack = new Stack[Int]
    stack.push(1)
    stack.push(2)
    stack.pop() should be (2)
    stack.pop() should be (1)
  }

  it should "throw NoSuchElementException if an empty stack is popped" in {
    val emptyStack = new Stack[Int]
    a [NoSuchElementException] should be thrownBy {
      emptyStack.pop()
    } 
  }
}

and IntelliJ (IDEA 2017.1.2) is showing me a warning for the usage of new Stack[Int]:

enter image description here

Searching for the warning showed me this issue: https://issues.scala-lang.org/browse/SI-9068

But I still have these questions:

  1. I get a popup which is splitted into two areas. Does it mean that there are two warnings, each with 2 lines. What is the real information? For the second area I see Reference must be prefixed and Under construction.

  2. Why I don't see the proper deprecated warning, like it was added here: https://github.com/scala/scala/pull/5260/files#diff-1ab096eae7e5571b6410a123567aac0aR57

  3. On github/API docs they sai: Use a List assigned to a var instead But I can't just replace Stack with List, because .push() is not available for that class. Or should I switch to the List API completely? And what's the difference between assigning the list with var or val? Can't I add items for instance via list.add(2) even if it was assigned with val?

I installed Scala 2.12.2 via Homebrew. I'm not sure if I'm IntelliJ it is using its own version, because I needed to download it via IntelliJ as well, but anyway it's the same version, so me setup looks like this: enter image description here


BTW: in the terminal / Scala REPL I get this output

scala> val stack = new Stack[Int]
<console>:14: warning: class Stack in package mutable is deprecated (since 2.12.0): Stack is an inelegant and potentially poorly-performing wrapper around List. Use a List assigned to a var instead.
       val stack = new Stack[Int]
                       ^

So the proper deprecation warning seems to work there.

timaschew
  • 16,254
  • 6
  • 61
  • 78

3 Answers3

9

Deprecated message

In general, when there are deprecated functions you see only the general response you saw. To get the detailed message you should compile with -deprecation. To change this use settings-> build, execution, deployment -> compiler -> scala compiler and check the relevant options (deprecation warnings in your case but most of the rest are probably a good idea)

Reference must be prefixed warning

This is a completely unrelated warning. When using mutable classes, the scala style is to prefix it using mutable. i.e. use this:

import collection.mutable    
val a = new mutable.Stack[Int]

instead of

import collection.mutable.Stack    
val a = new Stack[Int]

This is because the default mindset in scala should generally be to use immutable collections unless you have a good reason to do otherwise.

If this bothers you, you can always turn off this inspection.

What to do instead of stack

The reason stack was removed is that it is simply a wrapper around list. Push is simply adding a new head and pop is simply taking the tail.

This means that if you have:

val a = new mutable.Stack
a.push(XXX)
a.pop(XXX)

you can replace it with:

var a = new List
a = XXX +: a
a = a.tail

Note that in general, you can use immutable list here.

EDIT

Just to make sure it is more understandable, the List created in var a = new List should be replaced with an actual choice of list.

The standard way would be to use the standard scala creation methods e.g.:

var a = List[Int]()  
var a: List[Int] = Nil 

but it is also possible to choose another concrete list as needed if more functionality is required.

Assaf Mendelson
  • 12,701
  • 5
  • 47
  • 56
  • Changing the compiler settings did not help, I still see the same message with this settings: https://anonimag.es/image/JT9sfQ6 – timaschew May 11 '17 at 10:04
  • can you please paste the complete snippet how to replace the file I provide. It doesn't work for me to use `List`. I get: Class List is abstract, cannot be instantiated – timaschew May 11 '17 at 10:07
  • I added an explanation on the List creation options to the answer. As for the intellij compiler options, you are correct, my suggested fix handled the compilation (build) and not the inspection. I am not familiar with a way to change the inspection portion – Assaf Mendelson May 11 '17 at 14:05
  • it is better to use the prepend operation because it take O(1), and access the last inserted element via "head" e.g. var a = List[Int](); a = 1 :: a; a.head – Andrei Kaigorodov Jul 08 '17 at 01:07
  • 1
    was looking for explanation on *why* it was deprecated. got clear solution *how* to replace `push` and `pop`. cool answer. – hummingBird Jun 16 '18 at 12:53
  • `pop` doesn't take an argument, and it doesn't make sense to throw away the popped value as shown `a = a.tail`. – Abhijit Sarkar Jul 23 '18 at 09:16
  • yeah can someone elaborate on why it was deprecated in the first place? what's the potential performance issue and why wouldn't using a List var have the same issue? I like the convenience of the wrapper. – tksfz Jul 30 '18 at 03:54
  • `pop` is not the same as taking the `tail`. `pop` retrieves and removes the last element, whereas `tail` returns the list of items not including the head item. – Janac Meena Mar 04 '19 at 19:25
0

ListBuffer is a good replacement because it provides constant time prepend and removal. mutable.List is another choice. See https://stackoverflow.com/a/5753935/839733 for details.

Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219
0

And what's the difference between assigning the list with var or val? Can't I add items for instance via list.add(2) even if it was assigned with val?

You can assign a mutable ListBuffer (they don't make mutable List) to a val, or a regular immutable list to a var. it's up to you, but it's more functional to use immutable data structures. This is the part of your question that I think @abhijit-sarkar was addressing.

import scala.collection.mutable

object StackReplace{
  implicit class StackListBuffer[T](listBuffer:mutable.ListBuffer[T]){
    def push(t:T):Unit = listBuffer.prepend(t)
  }
  implicit class StackList[T](list:List[T]){
    def push(t:T):List[T] = t +: list
  }
}
import StackReplace._
val a = mutable.ListBuffer(1,2,3)
a.prepend(0)
a           // ListBuffer(0, 1, 2, 3)

var b = List(1,2,3)
b = 0 +: b  // List(0, 1, 2, 3)

a.push(-1)
a           // ListBuffer(-1, 0, 1, 2, 3)
b.push(-1)  // List(-1, 0, 1, 2, 3)

Implementing pop is left as an exercise to the reader.

Ion Freeman
  • 512
  • 4
  • 19