1

Suppose I have a class defined as

case class MyClass(myArray: Array[Int])

I want to only allow instances where the myArray parameter is of a specific length, say 3.

  1. Can I enforce that myArray.size == 3 at type/compile level?
  2. Would it be different with another collection? (say, an immutable list)

The only way I found to this is via a smart constructor at runtime, checking the size of myArray and failing - using for instance require.

1

2 Answers 2

6

Can I enforce that myArray.size == 3 at type/compile level?

Yes Scala can represent numbers at type-level. For example, using Sized from shapeless

import shapeless._
import syntax.sized._
import nat._

case class MyClass(myArray: Sized[Array[Int], _3])
MyClass(Sized[Array](1,2,3))         // ok
MyClass(Sized[Array](1,2,3,4))       // compile-time error

Array(1,2,3,4).sized(3).map(MyClass) // None

Here is how you might go about it in Scala 3 using scala.compiletime.ops facilities

import scala.compiletime.ops.int.S

enum MyArray[Size, +A]:
  case Nil extends MyArray[0, Nothing]
  case Cons[N <: Int, B](head: B, tail: MyArray[N, B]) extends MyArray[S[N], B]

import MyArray._

val xs: MyArray[3, Int] = Cons(1, Cons(2, Cons(3, Nil)))
val ys: MyArray[4, Int] = Cons(1, Cons(2, Cons(3, Cons(4, Nil))))

case class MyClass(myArray: MyArray[3, Int])
MyClass(xs) // ok
MyClass(ys) // compile-time error
Sign up to request clarification or add additional context in comments.

Comments

1

You can use require with everything you want :)

case class MyClass(myArray: Array[Int]) {
  require(myArray.size == 3, "Only arrays with 3 items are allowed!")
}

In case you pass an array that does not meet the requirement, it will throw an IllegalArgumentException.

2 Comments

Thanks for your answer, this is exactly what I meant with 'smart constructor'. I will update my question to make it clear 🙏
@ticofab this does NOT provide compile-time checking. This will throw a runtime exception, as an IllegalArgumentException when the require check fails

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.