Scala Array with different data types
Asked Answered
G

3

5

*as we know that scala array contains data of the same type. But when I declared array as

var a = new Array[Any](3)

I am able to store different data types.

a(0)=5
a(1)="hello"
a(2)=1.5

how is it possible? if it is wrong then what is the option we have in scala to store different data types?*

Gower answered 5/2, 2017 at 7:58 Comment(2)
I think a proper answer for this is too broad. Please consult one of the many Scala tutorialsFideicommissum
Your question suggests that you conceive of a value as having only a single, unique type. But it doesn't — in a language with subtyping, a value can be a member of many types at once.Clingstone
L
7

The notion of "same type" always depends on a level of generality. In Scala, the level of generality is determined by formal type.

Are 3 and 7 "of the same type"? If we write...

val a : Int = 3
val b : Int = 7

then they of of the same type Int. But, if we define bit-length restricted Int types (which we are very welcome to do in Scala), we might write

val a : Int2 = 3
val b : Int3 = 7

and they no longer appear to be of the same type!

If we define an inheritance hierarchy

trait Animal;
class Dog extends Animal;
class Frog extends Animal;

then do Dog and Frog have the same type? If we write

val d : Dog  = new Dog
val f : Frog = new Frog

then it looks like the answer is no. But if we write

val d : Animal = new Dog
val f : Animal = new Frog

then they look like they do have the same type. Consistent with that, if I declare an array like

val arr : Array[Dog] = Array.ofDim[Dog](5)

then I can't put a frog in it, because a frog is not a dog. But if I declare the a similar array

val arr : Array[Animal] = Array.ofDim[Animal](5)

Then of course both frogs and dogs can go in it, because at the level of generality of Animal, both Frogs and Dogs do have the same type.

In Scala Any is a base type from which all other types derive. So, at a very high level of generality, 5, "hello", and 1.5, all have the same type Any, just as at a high level of generality Frog and Dog have the same type Animal. So there's no problem putting 5, "hello", and 1.5 into an Array[Any].

Luncheon answered 5/2, 2017 at 8:44 Comment(0)
G
2

Yes you are right about scala array and you are indeed storing the data of same type here. See this example:

scala> val a = Array(5,"hello",1.5)
a: Array[Any] = Array(5, hello, 1.5)

We don't see that an array containing an integer,string and double is created. We see that an array of Any is created. During array creation, the scala compiler looked for the nearest common supertype in hierarchy to satisfy the property of Array that it can hold elements of same type only. And in this case, Any being the supertype of all the classes, satisfies the condition. And, if the compiler can't find the common supertype, Array creation will fail.

Note that, it's not just for Array, same goes for other collections that store same types.for eg: List

scala> val list = List(5,"hello",1.5)
list: List[Any] = List(5, hello, 1.5)

what is the option we have in scala to store different data types?

As you can see that we are not able to preserve the type of elements here in both List and Array. All the elements are being stored as Any. For preserving types of elements and storing them together, scala provides us with Tuple:

scala> val tuple = (5,"hello",1.5)
tuple: (Int, String, Double) = (5,hello,1.5)
Gauhati answered 5/2, 2017 at 10:47 Comment(1)
Is it a good practice to support array with different types (unless there is a hierarchy like you have in your example)? This can lead to dirty casting errorsMaladroit
B
0

As others have answered why Array[Any] can have elements of types String, Boolean, Int etc. let me answer the below part of the question

if it is wrong then what is the option we have in scala to store different data types?*

The most obvious answer is the Shapeless library. Shapeless supports an advanced data-structure called HList using which you can store heterogenous types in a list without losing the type information.

for example see the below snippet

scala> import shapeless.{::, HList, HNil}
import shapeless.{$colon$colon, HList, HNil}

scala> val list = 1 :: "a" :: true :: HNil
list: shapeless.::[Int,shapeless.::[String,shapeless.::[Boolean,shapeless.HNil]]] = 1 :: a :: true :: HNil

scala> list.head
res0: Int = 1 // notice the type of the element is Int and not Any

scala> list.tail.head
res1: String = a

scala> list.tail.tail.head
res2: Boolean = true

In the above code you have a val list of type HList with three elements of types Int, String and Boolean. And when you retrieve the elements of the HList the original type of the elements are preserved and you don't get a generic type like Any as in the case of Array. This is possible because HList stores not just data but the type information of the elements too and properly casts them on retrieval.

Bosomed answered 5/2, 2017 at 12:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.