Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enforcing non-emptyness of scala varargs at compile time

Tags:

scala

I have a function that expects a variable number of parameters of the same type, which sounds like the textbook use case for varargs:

def myFunc[A](as: A*) = ???

The problem I have is that myFunc cannot accept empty parameter lists. There's a trivial way of enforcing that at runtime:

def myFunc[A](as: A*) = {
  require(as.nonEmpty)
  ???
}

The problem with that is that it happens at runtime, as opposed to compile time. I would like the compiler to reject myFunc().

One possible solution would be:

def myFunc[A](head: A, tail: A*) = ???

And this works when myFunc is called with inline arguments, but I'd like users of my library to be able to pass in a List[A], which this syntax makes very awkward.

I could try to have both:

def myFunc[A](head: A, tail: A*) = myFunc(head +: tail)
def myFunc[A](as: A*) = ???

But we're right back where we started: there's now a way of calling myFunc with an empty parameter list.

I'm aware of scalaz's NonEmptyList, but in as much as possible, I'd like to stay with stlib types.

Is there a way to achieve what I have in mind with just the standard library, or do I need to accept some runtime error handling for something that really feels like the compiler should be able to deal with?

like image 899
Nicolas Rinaudo Avatar asked Oct 17 '16 20:10

Nicolas Rinaudo


1 Answers

What about something like this?

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

def myFunc()(implicit ev: Nothing) = ???
def myFunc[A](as: A*) = println(as)

// Exiting paste mode, now interpreting.

myFunc: ()(implicit ev: Nothing)Nothing <and> [A](as: A*)Unit
myFunc: ()(implicit ev: Nothing)Nothing <and> [A](as: A*)Unit

scala> myFunc(3)
WrappedArray(3)

scala> myFunc(List(3): _*)
List(3)

scala> myFunc()
<console>:13: error: could not find implicit value for parameter ev: Nothing
       myFunc()
             ^

scala> 

Replacing Nothing with a class that has an appropriate implicitNotFound annotation should allow for a sensible error message.

like image 124
Joe Pallas Avatar answered Sep 17 '22 14:09

Joe Pallas