{"id":50,"date":"2016-03-24T12:19:53","date_gmt":"2016-03-24T12:19:53","guid":{"rendered":"http:\/\/67bricks.com\/blog\/?p=50"},"modified":"2016-06-23T12:37:55","modified_gmt":"2016-06-23T12:37:55","slug":"command-line-parsing-with-scala-dynamic-and-macros","status":"publish","type":"post","link":"https:\/\/blog.67bricks.com\/?p=50","title":{"rendered":"Command line parsing with Scala dynamic and macros"},"content":{"rendered":"<p>In our developer meeting this week, we talked about using the Scala features of &#8220;dynamic&#8221; and macros to\u00a0simplify code for command-line parsing.<\/p>\n<p>The problem we were trying to solve is a recent project in which we have lots of separate command-line apps, with a lot of overlap between their arguments, but with a need for app-specific arguments and to apply different default parameters to each app.<\/p>\n<p><!--more--><\/p>\n<p>Our initial implementation was one big \u201call the command line arguments\u201d class, shared between everything, listing all of the arguments. It works, and it&#8217;s simple, but it&#8217;s a single, large shared dependency. We&#8217;re using Scallop as a command line parsing library.<\/p>\n<p>The first improved version was to use the Builder syntax for the Scallop command line parser &#8211; leading to code for accessing arguments like:<\/p>\n<blockquote><p>opts[String](\u201cbeanstalkHost\u201d),<br \/>\nopts[Int](\u201cbeanstalkPort\u201d)<\/p><\/blockquote>\n<p>This let groups of arguments be put into traits, so you could build up a command line app from a set of traits, one for accessing the beanstalk queue with the arguments that requires, one for accessing the REST datastore with the arguments that requires, and so on.<\/p>\n<p>Then, using scala.Dynamic, we\u00a0tried\u00a0a new\u00a0version that allows us to have a nicer syntax for accessing arguments like:<\/p>\n<blockquote><p>opt.beanstalkPort, opt.beanstalkPort<\/p><\/blockquote>\n<p>Where this is backed by a class\u00a0implementing Dynamic with an appropriate selectDynamic implementation:<\/p>\n<blockquote><p>def selectDynamic[T](fieldName: String)(implicit ev: TypeTag[T]): T = {<br \/>\nscallop[T](name)<br \/>\n}<\/p><\/blockquote>\n<p>But this allows argument\u00a0names to be mistyped, and the errors are only displayed at runtime. To get compile-time type checking\u00a0for arguments, we need to use a compile-time Scala macro, something like:<\/p>\n<blockquote><p>def selectDynamic(fieldName: String): String = macro ScallopMacro.checkSafety<br \/>\ndef checkSafety(c: blackbox.Context)(fieldName: c.Expr[String]): c.Expr[String] = {<br \/>\nimport c.universe._<br \/>\nval evalFieldName= c.eval(c.Expr[String](c.untypecheck(fieldName.tree.duplicate)))<br \/>\nprintln(&#8220;Compile time output &#8211; Eval field name is &#8220;+evalFieldName)<br \/>\nif (! isValid(evalFieldName)) {<br \/>\nc.error(c.enclosingPosition, s&#8221;Illegal field name $evalFieldName!&#8221;)<br \/>\n}<\/p>\n<p>val tree = q&#8221;opts.doSomething( $fieldName )&#8221;<br \/>\nc.Expr(tree)<br \/>\n}<\/p><\/blockquote>\n<p>This works &#8211;\u00a0and gives us compile-time\u00a0checks for argument names.<\/p>\n<p>However, our conclusion after doing all of this is that the added code complexity created by the use of dynamic and macros outweighed the benefits.\u00a0We&#8217;ve stuck with the simple approach that we had originally &#8211; it does mean a shared dependency, and a bit of code duplication, but the code is much simpler.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In our developer meeting this week, we talked about using the Scala features of &#8220;dynamic&#8221; and macros to\u00a0simplify code for command-line parsing. The problem we were trying to solve is a recent project in which we have lots of separate command-line apps, with a lot of overlap between their arguments, but with a need for &hellip; <a href=\"https:\/\/blog.67bricks.com\/?p=50\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Command line parsing with Scala dynamic and macros&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21],"tags":[],"class_list":["post-50","post","type-post","status-publish","format-standard","hentry","category-scala"],"_links":{"self":[{"href":"https:\/\/blog.67bricks.com\/index.php?rest_route=\/wp\/v2\/posts\/50","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.67bricks.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.67bricks.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.67bricks.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.67bricks.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=50"}],"version-history":[{"count":1,"href":"https:\/\/blog.67bricks.com\/index.php?rest_route=\/wp\/v2\/posts\/50\/revisions"}],"predecessor-version":[{"id":51,"href":"https:\/\/blog.67bricks.com\/index.php?rest_route=\/wp\/v2\/posts\/50\/revisions\/51"}],"wp:attachment":[{"href":"https:\/\/blog.67bricks.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=50"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.67bricks.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=50"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.67bricks.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=50"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}