7

I'm attempting to learn Scala so I have decided to implement datastructures with it. I've begun with the Stack. I have created the following Stack class.

class Stack[A : Manifest]() {

  var length:Int = -1
  var data = new Array[A](100)

  /**
   * Returns the size of the Stack.
  * @return the size of the stack
  */
 def size = {length} 

  /**
   * Returns the top element of the Stack without
   * removing it.
   * @return Stacks top element (not removed)
   */
  def peek[A] = {data(length)}

  /**
   * Informs the developer if the Stack is empty.
   * @return returns true if it is empty else false.
   */
  def isEmpty = {if(length==0)true else false}

  /**
   * Pushes the specified element onto the Stack.
   * @param The element to be pushed onto the Stack
   */
  def push(i: A){
    if(length+1 == data.size) reSize
    length+=1
    data(length) = i;
  }

  /**
   * Pops the top element off of the Stack.
   * @return the pop'd element.
   */
  def pop[A] = {
    length-=1
    data(length)
  }

  /**
   * Increases the size of the Stack by 100 indexes.
   */
  private def reSize{
    val oldData = data;
    data = new Array[A](length+101)
    for(i<-0 until length)data(i)=oldData(i)
   }
}

I Then attempt to initialize this class in my Java class using the following

Stack<Integer> stack = new Stack<Integer>();

However, I'm told that the constructor doesn't exist and that I should add an argument to match Manifest. Why does this happen and how can I fix it?

3 Answers 3

18

Alexey gave you the correct explanation but it is definitely possible to create manifest in you code (you just need a java.lang.Class object, which you can easily create in Java).

First you should add a java-friendly factory method to the companion object of Stack:

object Stack {
  def ofType[T]( klass: java.lang.Class[T] ) = {
    val manifest =  new Manifest[T] {
      def erasure = klass
    }
    new Stack()(manifest)
  }
}

This method will generated the appropriate manifest (from a java class) and will pass it explicitly to the Stack constructor. You can then use it from Java without pain:

Stack<String> stack = Stack.ofType( String.class );
stack.push( "Hello" );
stack.push( "World" );

System.out.println( stack.size() );
System.out.println( stack.peek() ); 
9

This happens because a context bound like [A : Manifest] is just a shorthand for an implicit constructor argument. So your class is "really" declared as class Stack[A]()(implicit m: Manifest[A]) {. So since the only way to create a Manifest is compiler magic (as far as I know), you can't do it from Java and can't construct a Stack there.

You can either change the design to avoid manifests, or create instances of Stack in Scala code and only use them from Java.

1
  • 1
    +1 for the explanation, but It is possible to create Manifest without compiler magic. See my answer. Commented Mar 25, 2012 at 16:51
2

Follow up on paradigmatic answer, you can also create a constructor for your class:

class Stack[A](implicit m: Manifest[A]) {

def this(clazz : Class[A]) {
  this()(new Manifest[A] {
    def erasure = clazz
  })
}

that can be then called from Java:

Stack<Integer> s = new Stack<Integer>(Integer.class);
s.push(1);
System.out.println(s.peek());

Nevertheless, the problem will be with generic types like having stacks of stacks of strings. For this you should look into this thread: http://www.scala-lang.org/node/7267

Not the answer you're looking for? Browse other questions tagged or ask your own question.