Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pattern match args and give error messages in a lightweight Scala script

I write a number of simple scala scripts that end up starting with a simple pattern match on args like:

val Array(path, foo, whatever) = args
// .. rest of the script uses "path", "foo", etc.

Of course, if I supply the wrong number of arguments, I get an inscrutable error like:

scala.MatchError: [Ljava.lang.String;@7786df0f
    at Main$$anon$1.<init>(FollowUsers.scala:5)
    ...

Is there an easy way to give a more useful error message? My current workaround is to do something like:

args match {
  case Array(path, foo, whatever) => someFunction(path, foo, whatever)
  case _ => System.err.println("usage: path foo whatever")
}
def someFunction(path: String, foo: String, whatever: String) = {
  // .. rest of the script uses "path", "foo", etc.
}

But that feels like a lot of boilerplate what with having to define a whole other function, and having to repeat "path", "foo" and "whatever" in so many places. Is there a better way? I guess I could lose the function and put the body in the match statement, but that seems less readable to me.

I know I could use one of the many command line argument parsing packages, but I'm really looking for something extremely lightweight that I don't have to add a dependency and modify my classpath for.

like image 698
Steve Avatar asked Sep 10 '10 10:09

Steve


3 Answers

How about?

val Array(path, foo, whatever) = if (args.length == 3) args 
  else throw new Exception("usage:path foo whatever")

==edit==

based on Randall's comment:

require(args.length == 3, "usage: path foo whatever")
val Array(path, foo, whatever) = args

That's minimum boilerplate. Your vals are in scope, you don't have to deal with closing brace and you get the usage error message.

like image 197
huynhjl Avatar answered Oct 05 '22 11:10

huynhjl


scala> val args = Array("evil", "mad", "scientist")
args: Array[java.lang.String] = Array(evil, mad, scientist)

scala> def logToConsole(th: Throwable) { Console.err.println("Usage: path foo bar") }
logToConsole: (th: Throwable)Unit

scala> handling(classOf[MatchError]) by logToConsole apply {
     |   val Array(path, foo, bar) = args
     |   println(path)
     | }
evil

scala> handling(classOf[MatchError]) by logToConsole apply {
     |   val Array(path, foo, bar) = Array("#fail")
     |   println(path)
     | }
Usage: path foo bar
like image 40
missingfaktor Avatar answered Oct 05 '22 12:10

missingfaktor


One way is to catch MatchError:

try {
  val Array(path, foo, whatever) = args
} catch {
  case _: MatchError => System.err.println("usage: path foo whatever")
}
like image 32
michid Avatar answered Oct 05 '22 12:10

michid