1

Im having troubles when trying to initialize an array with a generic type and storing it in a value (val)

case class Matrix[T <: AnyVal](val structure : Array[Array[Array[T]]])

//A method in another class
def foo() : Unit = {
    val aux: Array[Array[Array[T]]] = Array.fill(this.structure.length, this.structure.head.length, this.structure.head.head.length)(null)
    ...
    ...
}

The problem is that, when trying to create an array of type T, I want to initialize it with a default value of null, but it says that:

Expression of type Array[Array[Array[T]]] doesn't conform to expected type Array[Array[Array[T]]]

How can I solve this problem? Thank you

5
  • AnyVals cannot be null. Commented Dec 28, 2016 at 18:49
  • You are right. I just noticed it. But, which is the equivalent of null by for AnyVal? Commented Dec 28, 2016 at 18:55
  • You are looking for AnyRef. Commented Dec 28, 2016 at 18:57
  • Still thrown type mismatch: found Null(null), required: T Commented Dec 28, 2016 at 19:07
  • If you're talking about the val aux then perhaps you should declare your T. It feels like you are missing too much code here for us to be able to help you. Commented Dec 28, 2016 at 19:16

2 Answers 2

3

T:Numeric

If I were you I would restrict T to Numeric types and then use the zero value as the default value for an empty matrix:

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

import scala.reflect.ClassTag

class Matrix[T:Numeric](val structure: Array[Array[T]])
{
    def *(that: Matrix[T]): Matrix[T] = ???
    def +(that: Matrix[T]): Matrix[T] = ???
    override def toString: String = structure.map(_.mkString(",")).mkString("\n")
}

object Matrix
{
    def apply[T:Numeric:ClassTag](rows: Int, cols: Int): Matrix[T] =
    {
        val zero: T = implicitly[Numeric[T]].zero
        new Matrix[T](Array.fill[T](rows, cols)(zero))
    }

    def apply[T:Numeric](data: Array[Array[T]]): Matrix[T] = new Matrix(data)
}

// Exiting paste mode, now interpreting.

import scala.reflect.ClassTag
defined class Matrix
defined object Matrix

scala> val empty = Matrix[Int](3,3)
empty: Matrix[Int] =
0,0,0
0,0,0
0,0,0

scala> val ex = Matrix[Int](Array(Array(1,2), Array(3,4)))
ex: Matrix[Int] =
1,2
3,4

T <: AnyRef

Otherwise if you want to use non-numeric values with null as default you can do something like this:

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

import scala.reflect.ClassTag

class Matrix[T >: Null <: AnyRef](val structure : Array[Array[T]])
{
    override def toString: String = structure.map(_.mkString(",")).mkString("\n")
}

object Matrix
{
    def apply[T >: Null <: AnyRef : ClassTag](rows: Int, cols: Int): Matrix[T] =
    {
        new Matrix[T](Array.fill[T](rows, cols)(null))
    }

    def apply[T >: Null <: AnyRef](data: Array[Array[T]]): Matrix[T] = new Matrix(data)
}

// Exiting paste mode, now interpreting.

import scala.reflect.ClassTag
defined class Matrix
defined object Matrix

scala> case class Person(name: String)
defined class Person

scala> val empty = Matrix[Person](3,3)
empty: Matrix[Person] =
null,null,null
null,null,null
null,null,null

scala> val data = Array(Array(Person("a"), Person("b")), Array(Person("c"), Person("d")))
data: Array[Array[Person]] = Array(Array(Person(a), Person(b)), Array(Person(c), Person(d)))

scala> val ex = Matrix[Person](data)
ex: Matrix[Person] =
Person(a),Person(b)
Person(c),Person(d)

Note that you must manually specify that T can be a supertype of Null by adding the bound T >: Null.

Sign up to request clarification or add additional context in comments.

5 Comments

The thing is that I algo want to use the matrix to contain other data type, not only Numeric values. That's why I want to initialize an array with a default value, and asign it to a variable (or value in this case)
Fair enough, but the general idea still holds that your default value will need to be of type T (so if you can restrict T to some tight supertype of your data and then use a value of that supertype then that would be ideal)
For example, in Java, all classes have Object like last parent. So, the default value of Object when creating an array is null. In Scala, which is the default value? There should be something similar. I know that Scala "doesn't like" nulls, and thats why they use Options, but I think there should be a default value like null but for Scala.
You need to say that it can be null explicitly using a T >: Null <: AnyRef, see my updated answer
@Malvrok does this answer your question?
1

If you want the default value, just use Array.ofDim(this.structure.length, this.structure.head.length, this.structure.head.head.length) instead of Array.fill. The values will be, like in Java, null for objects, 0 for Int, 0.0 for Double, etc. It's cheaper as well.

You'll need a ClassTag[T] in scope, but you need it for fill as well.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.