- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Re: parsing command-line options and arguments
Mon, 2010-03-15, 06:39
How complex is the command line syntax?
-------------------------------------
Russ Paielli wrote:
Yes, I found that link when I googled, but it is very sketchy. Is something
available in the standard Scala (or Java) library?
If not, what is the simplest and cleanest way to process command-line
options and arguments? The gnu port of getopt to Java looks more familiar to
me than the other alternatives. Is it a good alternative for Scala? Thanks.
Russ P.
On Sun, Mar 14, 2010 at 9:15 PM, Daniel Sobral wrote:
>
> http://stackoverflow.com/questions/2315912/scala-best-way-to-parse-comma...
>
>
> On Sun, Mar 14, 2010 at 11:03 PM, Russ Paielli wrote:
>
>> Python has "getopt" to parse command-line options and arguments. Does
>> Scala (or Java) have something like it? Thanks.
>>
>> Russ P.
>>
>> --
>> http://RussP.us
>>
>
>
>
> --
> Daniel C. Sobral
>
> I travel to the future all the time.
>
Mon, 2010-03-15, 07:17
#2
Re: parsing command-line options and arguments
On Sun, Mar 14, 2010 at 10:39 PM, Naftoli Gugenheim <naftoligug@gmail.com> wrote:
Very basic. Just "-a" or "--minAlt 180" type stuff, as you would see with Python "getopt." I'm surprised something this basic isn't available in the standard Scala or Java libraries. Score one for Python. (Scala is still way ahead!)
Russ P.
--
http://RussP.us
How complex is the command line syntax?
Very basic. Just "-a" or "--minAlt 180" type stuff, as you would see with Python "getopt." I'm surprised something this basic isn't available in the standard Scala or Java libraries. Score one for Python. (Scala is still way ahead!)
Russ P.
-------------------------------------
Russ Paielli<russ.paielli@gmail.com> wrote:
Yes, I found that link when I googled, but it is very sketchy. Is something
available in the standard Scala (or Java) library?
If not, what is the simplest and cleanest way to process command-line
options and arguments? The gnu port of getopt to Java looks more familiar to
me than the other alternatives. Is it a good alternative for Scala? Thanks.
Russ P.
On Sun, Mar 14, 2010 at 9:15 PM, Daniel Sobral <dcsobral@gmail.com> wrote:
>
> http://stackoverflow.com/questions/2315912/scala-best-way-to-parse-command-line-parameters-cli
>
>
> On Sun, Mar 14, 2010 at 11:03 PM, Russ Paielli <russ.paielli@gmail.com>wrote:
>
>> Python has "getopt" to parse command-line options and arguments. Does
>> Scala (or Java) have something like it? Thanks.
>>
>> Russ P.
>>
>> --
>> http://RussP.us
>>
>
>
>
> --
> Daniel C. Sobral
>
> I travel to the future all the time.
>
--
http://RussP.us
--
http://RussP.us
Wed, 2010-03-17, 03:17
#3
Re: parsing command-line options and arguments
On Sun, 14 Mar 2010 23:13:41 -0700, Russ Paielli wrote:
> On Sun, Mar 14, 2010 at 10:39 PM, Naftoli Gugenheim
> wrote:
>
>> How complex is the command line syntax?
>>
>>
> Very basic. Just "-a" or "--minAlt 180" type stuff, as you would see
> with Python "getopt."
Getopt isn't very basic at all. Getopt knows how to deal with short
switches (with one-letter names and a single dash) all being combined
into a single switch (e.g. ls -al), several styles of specifying long
options (--minAlt 180 is the same as --minAlt=180), using a double-dash
with no name (--) to supress further command-line option handling, and
how to filter out arguments that aren't switches from between the
switches.
> I'm surprised something this basic isn't available
> in the standard Scala or Java libraries. Score one for Python. (Scala is
> still way ahead!)
That's because Python is originally a UNIX language where command-line
options (particularly in this style) are a daily occurance. By contrast,
Java and Python are portable languages for Mac, Windows, cell phones, and
other stuff too. The syntax used on Windows is different. MacOS (before
OS X) never had command-line options, and cell phones still dont. It's a
library intended for one platform. They don't make it standard so you
don't base your interface on it.
Thu, 2010-03-18, 01:57
#4
Re: Re: parsing command-line options and arguments
I got interested in this command-line parsing problem, and I probably spent more time on it than I should have, but I came up with something that I think is pretty nifty. Why not have a command-line syntax that is similar to the syntax for passing arguments to a method? Here is what I came up with. Comments and suggestions welcome.
CommandLineParser.scala:
/*****************************************************************************
The CommandLineParser by Russ Paielli parses command-line arguments in a
style similar to scala method calls with named arguments. For example, a
program could be invoked as
myProgram x=123, 22, zz = blah, 43.5, y=true, gg, rr=3.445
The comma-separated fields can be either assignment-style options (if
"=" is used) or regular arguments. The regular and assignment-style
options can be interwoven arbitrarily. The assignment-style options are
accessed by the name on the left side of the assignment (a String), and
regular arguments are accessed by an integer index starting with
1. Methods are provided to read arguments of type Int, Double, String,
and Boolean. The user can specify an optional list of valid arguments if
desired, in which case an invalid argument will throw an Exception.
Here is an example of its usage:
def main(args: Array[String]) {
val options = List("x", "y", "zz", "rr", "k", "a") // valid options
val CL = new CommandLineParser(args, options)
val x = CL.Int("x")
val k = CL.Int("k", -33) // -33 is the default value if "k" is not found
val rr = CL.Real("rr") // "Real" is an alias for Double
val zz = CL.String("zz")
val a2 = CL.Real(2) // regular argument accessed with Int index
val y = CL.Boolean("y")
val a1 = CL.Int(1) // regular argument with no default
val a3 = CL.Int(5, 22) // regular argument with default value 22
}
******************************************************************************/
import scala.collection.mutable.ListBuffer
import scala.collection.mutable.Map
class CommandLineParser(input: Array[String],
val options: List[String]=List[String]()) {
private val map = Map[String, String]()
private val args = ListBuffer[String]()
private def initialize(input: Array[String]): Int = {
val array = input.mkString(" ").split(",")
for (item <- array) {
if (item.contains("=")) { // assignment-style arguments
val pair = item.split("=")
val key = pair(0).trim
val value = pair(1).trim
map(key) = value
}
else args.append(item.trim) // regular (non-assignment) arguments
}
args.length // number of regular (non-assignment) arguments
}
private val Narg = initialize(input) // number of non-assignment arguments
private def checkOption(option: String) {
if (options.isEmpty) return // no list of valid options provided
if (options.contains(option)) return
val message = "Invalid command-line option: " + option
throw new RuntimeException(message)
}
private def isSet(option: String): Boolean = {
checkOption(option)
if (map.contains(option)) true else false
}
def String(option: String, default: String=""): String =
if (isSet(option)) map(option) else default
def Int(option: String, default: Int=0): Int =
if (isSet(option)) map(option).toInt else default
def Real(option: String, default: Double=0): Double =
if (isSet(option)) map(option).toDouble else default
def Boolean(option: String, default: Boolean=false): Boolean =
if (isSet(option)) map(option).toBoolean else default
def Int(i: Int) = args(i-1).toInt
def Real(i: Int) = args(i-1).toDouble
def String(i: Int) = args(i-1)
def Boolean(i: Int) = args(i-1).toBoolean
def Int(i: Int, d: Int) = if (Narg >= i) args(i-1).toInt else d
def Real(i: Int, d: Double) = if (Narg >= i) args(i-1).toDouble else d
def String(i: Int, d: String) = if (Narg >= i) args(i-1) else d
def Boolean(i: Int, d: Boolean) = if (Narg >= i) args(i-1).toBoolean else d
}
CommandLineParser.scala:
/*****************************************************************************
The CommandLineParser by Russ Paielli parses command-line arguments in a
style similar to scala method calls with named arguments. For example, a
program could be invoked as
myProgram x=123, 22, zz = blah, 43.5, y=true, gg, rr=3.445
The comma-separated fields can be either assignment-style options (if
"=" is used) or regular arguments. The regular and assignment-style
options can be interwoven arbitrarily. The assignment-style options are
accessed by the name on the left side of the assignment (a String), and
regular arguments are accessed by an integer index starting with
1. Methods are provided to read arguments of type Int, Double, String,
and Boolean. The user can specify an optional list of valid arguments if
desired, in which case an invalid argument will throw an Exception.
Here is an example of its usage:
def main(args: Array[String]) {
val options = List("x", "y", "zz", "rr", "k", "a") // valid options
val CL = new CommandLineParser(args, options)
val x = CL.Int("x")
val k = CL.Int("k", -33) // -33 is the default value if "k" is not found
val rr = CL.Real("rr") // "Real" is an alias for Double
val zz = CL.String("zz")
val a2 = CL.Real(2) // regular argument accessed with Int index
val y = CL.Boolean("y")
val a1 = CL.Int(1) // regular argument with no default
val a3 = CL.Int(5, 22) // regular argument with default value 22
}
******************************************************************************/
import scala.collection.mutable.ListBuffer
import scala.collection.mutable.Map
class CommandLineParser(input: Array[String],
val options: List[String]=List[String]()) {
private val map = Map[String, String]()
private val args = ListBuffer[String]()
private def initialize(input: Array[String]): Int = {
val array = input.mkString(" ").split(",")
for (item <- array) {
if (item.contains("=")) { // assignment-style arguments
val pair = item.split("=")
val key = pair(0).trim
val value = pair(1).trim
map(key) = value
}
else args.append(item.trim) // regular (non-assignment) arguments
}
args.length // number of regular (non-assignment) arguments
}
private val Narg = initialize(input) // number of non-assignment arguments
private def checkOption(option: String) {
if (options.isEmpty) return // no list of valid options provided
if (options.contains(option)) return
val message = "Invalid command-line option: " + option
throw new RuntimeException(message)
}
private def isSet(option: String): Boolean = {
checkOption(option)
if (map.contains(option)) true else false
}
def String(option: String, default: String=""): String =
if (isSet(option)) map(option) else default
def Int(option: String, default: Int=0): Int =
if (isSet(option)) map(option).toInt else default
def Real(option: String, default: Double=0): Double =
if (isSet(option)) map(option).toDouble else default
def Boolean(option: String, default: Boolean=false): Boolean =
if (isSet(option)) map(option).toBoolean else default
def Int(i: Int) = args(i-1).toInt
def Real(i: Int) = args(i-1).toDouble
def String(i: Int) = args(i-1)
def Boolean(i: Int) = args(i-1).toBoolean
def Int(i: Int, d: Int) = if (Narg >= i) args(i-1).toInt else d
def Real(i: Int, d: Double) = if (Narg >= i) args(i-1).toDouble else d
def String(i: Int, d: String) = if (Narg >= i) args(i-1) else d
def Boolean(i: Int, d: Boolean) = if (Narg >= i) args(i-1).toBoolean else d
}
Thu, 2010-03-18, 09:47
#5
Re: Re: parsing command-line options and arguments
Hate to be a spoiler but I think this isn't the super stuff you are making it out to be as it goes clearly against what people are used to.
On most OSes commands are started using the -command notation and I believe it makes sense to go by this.
-Stefan
2010/3/18 Russ Paielli <russ.paielli@gmail.com>
On most OSes commands are started using the -command notation and I believe it makes sense to go by this.
-Stefan
2010/3/18 Russ Paielli <russ.paielli@gmail.com>
I got interested in this command-line parsing problem, and I probably spent more time on it than I should have, but I came up with something that I think is pretty nifty. Why not have a command-line syntax that is similar to the syntax for passing arguments to a method? Here is what I came up with. Comments and suggestions welcome.
Thu, 2010-03-18, 19:07
#6
Re: Re: parsing command-line options and arguments
On Thu, Mar 18, 2010 at 1:39 AM, Stefan Langer <mailtolanger@googlemail.com> wrote:
The "-command" notation originated with low-level scripting languages such as bash, and it makes sense there, but I think we can do better for high-level languages such as Scala. Ultimately it boils down to personal preference, but I have difficulty understanding how anyone could actually prefer the "-command" notation to what I proposed for any reason other than that they are more familiar with it. If we never changed any conventions that we are familiar with, we'd still be using FORTRAN.
Having said that, I really don't care if others adopt my idea or not. If you like it, use it. If not, don't. I like it, and I see no reason not to use it myself, so I will.
Russ P.
Hate to be a spoiler but I think this isn't the super stuff you are making it out to be as it goes clearly against what people are used to.
On most OSes commands are started using the -command notation and I believe it makes sense to go by this.
The "-command" notation originated with low-level scripting languages such as bash, and it makes sense there, but I think we can do better for high-level languages such as Scala. Ultimately it boils down to personal preference, but I have difficulty understanding how anyone could actually prefer the "-command" notation to what I proposed for any reason other than that they are more familiar with it. If we never changed any conventions that we are familiar with, we'd still be using FORTRAN.
Having said that, I really don't care if others adopt my idea or not. If you like it, use it. If not, don't. I like it, and I see no reason not to use it myself, so I will.
Russ P.
Sat, 2010-03-20, 23:27
#7
Re: Re: parsing command-line options and arguments
On Thu, Mar 18, 2010 at 11:05 AM, Russ Paielli <russ.paielli@gmail.com> wrote:
Well, maybe I do care a little bit. I added a little feature so that you can write "sb=t" as shorthand for "sb=true" (I like to avoid line wraps if possible). That's only one character longer than "-sb". I also corrected a minor bug so that options set on the command line are correctly checked for validity. Here's the new version of CommandLine.scala:
/*****************************************************************************
The CommandLine class by Russ Paielli parses command-line arguments in a
style similar to scala method calls with named arguments. For example, a
program could be invoked with the command line
myProgram x=123, 22, zz = blah, 43.5, y=t, gg, rr=3.445
The comma-delimited fields can be either assignment-style options (if
"=" is used) or regular arguments. The regular and assignment-style
options can be interwoven arbitrarily. The assignment-style options are
accessed by the name on the left side of the assignment (a String), and
regular arguments are accessed by an integer index (starting with
1). Methods are provided to read arguments of type Int, Double, String,
and Boolean. Booleans can be specified as "t" for "true" or "f" for
"false". The user can specify an optional list of valid options if
desired, in which case an Exception will be thrown if an invalid option
is detected.
Here is an example of its usage (assuming the command line shown above):
def main(args: Array[String]) {
val options = List("x", "y", "zz", "rr", "k", "a") // valid options
val com = new CommandLine(args, options) // "options" is optional!
val x = com.int("x") // read "x" and convert it to an integer
val k = com.int("k", -33) // -33 is the default value if "k" is not found
val rr = com.real("rr") // read "rr" an convert it to a Double
val zz = com.str("zz") // read "zz" as a String
val a2 = com.real(2) // regular argument accessed with Int index
val y = com.bool("y")
val a1 = com.int(1) // regular argument with no default
val a3 = com.int(5, 22) // regular argument with default value 22
}
******************************************************************************/
import scala.collection.mutable.ListBuffer
import scala.collection.mutable.Map
class CommandLine(input: Array[String], val options: List[String]=Nil) {
private val map = Map[String, String]()
private val args = ListBuffer[String]()
private def checkOption(option: String) {
// check if an option is in the list of valid options (if provided)
if (options.isEmpty) return // empty list of valid options, skip check
if (options.contains(option)) return
val message = "Invalid command-line option: " + option
throw new RuntimeException(message)
}
private def initialize(input: Array[String]): Int = {
for (item <- input.mkString(" ").split(",")) {
if (item.contains("=")) { // assignment-style argument
val pair = item.split("=")
val key = pair(0).trim
val value = pair(1).trim
checkOption(key)
map(key) = value
}
else args.append(item.trim) // regular (non-assignment) arguments
}
args.length // number of regular (non-assignment) arguments
}
private val Narg = initialize(input) // number of non-assignment arguments
private def isSet(option: String): Boolean = { // check if option is set
checkOption(option)
if (map.contains(option)) true else false
}
private def boolx(str: String): String = str match { // shorthand for boolean
case "t" => "true"
case "f" => "false"
case _ => str
}
// read assignment-style options:
def str(option: String, default: String=""): String = // read a String
if (isSet(option)) map(option) else default
def int(option: String, default: Int=0): Int = // read an Int
if (isSet(option)) map(option).toInt else default
def real(option: String, default: Double=0): Double = // read a Double
if (isSet(option)) map(option).toDouble else default
def bool(option: String, default: Boolean=false): Boolean = // read a Boolean
if (isSet(option)) boolx(map(option)).toBoolean else default
// read regular arguments, with default if argument not provided:
def str(i: Int, default: String) =
if (Narg >= i) args(i-1) else default
def int(i: Int, default: Int) =
if (Narg >= i) args(i-1).toInt else default
def real(i: Int, default: Double) =
if (Narg >= i) args(i-1).toDouble else default
def bool(i: Int, default: Boolean) =
if (Narg >= i) boolx(args(i-1)).toBoolean else default
// read regular arguments, with no default (mandatory arguments):
def str(i: Int) = args(i-1) // read a String, no default (mandatory arg)
def int(i: Int) = args(i-1).toInt
def real(i: Int) = args(i-1).toDouble
def bool(i: Int) = boolx(args(i-1)).toBoolean
}
The "-command" notation originated with low-level scripting languages such as bash, and it makes sense there, but I think we can do better for high-level languages such as Scala. Ultimately it boils down to personal preference, but I have difficulty understanding how anyone could actually prefer the "-command" notation to what I proposed for any reason other than that they are more familiar with it. If we never changed any conventions that we are familiar with, we'd still be using FORTRAN.
Having said that, I really don't care if others adopt my idea or not. If you like it, use it. If not, don't. I like it, and I see no reason not to use it myself, so I will.
Well, maybe I do care a little bit. I added a little feature so that you can write "sb=t" as shorthand for "sb=true" (I like to avoid line wraps if possible). That's only one character longer than "-sb". I also corrected a minor bug so that options set on the command line are correctly checked for validity. Here's the new version of CommandLine.scala:
/*****************************************************************************
The CommandLine class by Russ Paielli parses command-line arguments in a
style similar to scala method calls with named arguments. For example, a
program could be invoked with the command line
myProgram x=123, 22, zz = blah, 43.5, y=t, gg, rr=3.445
The comma-delimited fields can be either assignment-style options (if
"=" is used) or regular arguments. The regular and assignment-style
options can be interwoven arbitrarily. The assignment-style options are
accessed by the name on the left side of the assignment (a String), and
regular arguments are accessed by an integer index (starting with
1). Methods are provided to read arguments of type Int, Double, String,
and Boolean. Booleans can be specified as "t" for "true" or "f" for
"false". The user can specify an optional list of valid options if
desired, in which case an Exception will be thrown if an invalid option
is detected.
Here is an example of its usage (assuming the command line shown above):
def main(args: Array[String]) {
val options = List("x", "y", "zz", "rr", "k", "a") // valid options
val com = new CommandLine(args, options) // "options" is optional!
val x = com.int("x") // read "x" and convert it to an integer
val k = com.int("k", -33) // -33 is the default value if "k" is not found
val rr = com.real("rr") // read "rr" an convert it to a Double
val zz = com.str("zz") // read "zz" as a String
val a2 = com.real(2) // regular argument accessed with Int index
val y = com.bool("y")
val a1 = com.int(1) // regular argument with no default
val a3 = com.int(5, 22) // regular argument with default value 22
}
******************************************************************************/
import scala.collection.mutable.ListBuffer
import scala.collection.mutable.Map
class CommandLine(input: Array[String], val options: List[String]=Nil) {
private val map = Map[String, String]()
private val args = ListBuffer[String]()
private def checkOption(option: String) {
// check if an option is in the list of valid options (if provided)
if (options.isEmpty) return // empty list of valid options, skip check
if (options.contains(option)) return
val message = "Invalid command-line option: " + option
throw new RuntimeException(message)
}
private def initialize(input: Array[String]): Int = {
for (item <- input.mkString(" ").split(",")) {
if (item.contains("=")) { // assignment-style argument
val pair = item.split("=")
val key = pair(0).trim
val value = pair(1).trim
checkOption(key)
map(key) = value
}
else args.append(item.trim) // regular (non-assignment) arguments
}
args.length // number of regular (non-assignment) arguments
}
private val Narg = initialize(input) // number of non-assignment arguments
private def isSet(option: String): Boolean = { // check if option is set
checkOption(option)
if (map.contains(option)) true else false
}
private def boolx(str: String): String = str match { // shorthand for boolean
case "t" => "true"
case "f" => "false"
case _ => str
}
// read assignment-style options:
def str(option: String, default: String=""): String = // read a String
if (isSet(option)) map(option) else default
def int(option: String, default: Int=0): Int = // read an Int
if (isSet(option)) map(option).toInt else default
def real(option: String, default: Double=0): Double = // read a Double
if (isSet(option)) map(option).toDouble else default
def bool(option: String, default: Boolean=false): Boolean = // read a Boolean
if (isSet(option)) boolx(map(option)).toBoolean else default
// read regular arguments, with default if argument not provided:
def str(i: Int, default: String) =
if (Narg >= i) args(i-1) else default
def int(i: Int, default: Int) =
if (Narg >= i) args(i-1).toInt else default
def real(i: Int, default: Double) =
if (Narg >= i) args(i-1).toDouble else default
def bool(i: Int, default: Boolean) =
if (Narg >= i) boolx(args(i-1)).toBoolean else default
// read regular arguments, with no default (mandatory arguments):
def str(i: Int) = args(i-1) // read a String, no default (mandatory arg)
def int(i: Int) = args(i-1).toInt
def real(i: Int) = args(i-1).toDouble
def bool(i: Int) = boolx(args(i-1)).toBoolean
}
Sat, 2010-03-20, 23:47
#8
Re: Re: parsing command-line options and arguments
On Saturday March 20 2010, Russ Paielli wrote:
> On Thu, Mar 18, 2010 at 11:05 AM, Russ Paielli wrote:
> > The "-command" notation originated with low-level scripting
> > languages such as bash, and it makes sense there, but I think we
> > can do better for high-level languages such as Scala. Ultimately it
> > boils down to personal preference, but I have difficulty
> > understanding how anyone could actually prefer the "-command"
> > notation to what I proposed for any reason other than that they are
> > more familiar with it. If we never changed any conventions that we
> > are familiar with, we'd still be using FORTRAN.
Aren't we talking about the command-invocation processing for programs
that just happen to be written in our current all-time-favorite
language, Scala?
As far as preference and familiarity: De gustibus non est disputandum.
Bit don't bad-mouth FORTRAN. It had to walk 5 miles to and from school,
uphill both ways in a blizzard every day, 6 days a week, 48 weeks each
year.
> > Having said that, I really don't care if others adopt my idea or
> > not. If you like it, use it. If not, don't. I like it, and I see no
> > reason not to use it myself, so I will.
>
> Well, maybe I do care a little bit. I added a little feature so that
> you can write "sb=t" as shorthand for "sb=true" (I like to avoid line
> wraps if possible). That's only one character longer than "-sb". I
> also corrected a minor bug so that options set on the command line
> are correctly checked for validity. Here's the new version of
> CommandLine.scala:
This notation is even older and goes back to one of the IBM systems,
JCL, I think. It has to my knowledge exactly one representative in the
Unix / Linux world: The "dd" command.
For what little it's worth, I think this is a reasonable model. In fact,
when I wrote my own command-line parser, I included support for this
kind of option as well as the POSIX "getopt" style. Any given command
definition may include either or both these styles.
> ... For example, a program could be invoked with the command line
>
> myProgram x=123, 22, zz = blah, 43.5, y=t, gg, rr=3.445
I do not favor the use of commas to separate arguments.
> ...
Randall Schulz
Sun, 2010-03-21, 00:27
#9
Re: Re: parsing command-line options and arguments
On Sat, Mar 20, 2010 at 3:43 PM, Randall R Schulz <rschulz@sonic.net> wrote:
On Saturday March 20 2010, Russ Paielli wrote:
> On Thu, Mar 18, 2010 at 11:05 AM, Russ Paielli wrote:
> > The "-command" notation originated with low-level scripting
> > languages such as bash, and it makes sense there, but I think we
> > can do better for high-level languages such as Scala. Ultimately it
> > boils down to personal preference, but I have difficulty
> > understanding how anyone could actually prefer the "-command"
> > notation to what I proposed for any reason other than that they are
> > more familiar with it. If we never changed any conventions that we
> > are familiar with, we'd still be using FORTRAN.
Aren't we talking about the command-invocation processing for programs
that just happen to be written in our current all-time-favorite
language, Scala?
Yes.
As far as preference and familiarity: De gustibus non est disputandum.
Bit don't bad-mouth FORTRAN. It had to walk 5 miles to and from school,
uphill both ways in a blizzard every day, 6 days a week, 48 weeks each
year.
I understand that Fortran is still used for heavy-duty number crunching, as in finite-element analysis and such. At least it was a few years ago. But it does have its limitations outside of that arena, of course. I have a colleague in his 70's who is a wiz at numerical analysis and algorithms, but I don't think he understands why we aren't all still using Fortran.
> > Having said that, I really don't care if others adopt my idea or
> > not. If you like it, use it. If not, don't. I like it, and I see no
> > reason not to use it myself, so I will.
>
> Well, maybe I do care a little bit. I added a little feature so that
> you can write "sb=t" as shorthand for "sb=true" (I like to avoid line
> wraps if possible). That's only one character longer than "-sb". I
> also corrected a minor bug so that options set on the command line
> are correctly checked for validity. Here's the new version of
> CommandLine.scala:
This notation is even older and goes back to one of the IBM systems,
JCL, I think. It has to my knowledge exactly one representative in the
Unix / Linux world: The "dd" command.
For what little it's worth, I think this is a reasonable model. In fact,
when I wrote my own command-line parser, I included support for this
kind of option as well as the POSIX "getopt" style. Any given command
definition may include either or both these styles.
Yes, the "getopt" style is perfectly suitable for certain kinds of applications. The main reason I wrote my own parser is that it seemed easier and more fun than figuring out how to use the available alternatives.
I found that the commas simplify parsing, and they also mimic the familiar syntax of arguments passed to a method.
> ... For example, a program could be invoked with the command line
>
> myProgram x=123, 22, zz = blah, 43.5, y=t, gg, rr=3.445
I do not favor the use of commas to separate arguments.
Russ P.
Sun, 2010-03-21, 04:47
#10
Re: Re: parsing command-line options and arguments
I find args4j [1] much easier (being declarative) and more powerful to use, even though it was written for Java not Scala.
You setup a configuration class declaratively like so:
import org.kohsuke.args4j._
class Cli {
var file: File = null
@Option{val name = "-f", val usage = "The input file to process"}
def setFile(file: File) = this.file = file
var help: Boolean = false
@Option{val name = "-h", val usage = "Displays usage help"}
def setHelp(help: Boolean) = this.help = help
}
(Having to explicitly declare the extra "setter" defs instead of using Scala's handy @BeanProperty is an unfortunate necessity due to the way args4j processes the annotations)
You can then use it like so:
object MyApp {
def main (args: Array[String]) : Unit = {
val cli = new Cli
val parser = new CmdLineParser(cli)
try {
parser.parseArgument(args)
if(cli.help) {
parser.printUsage(System.out)
}else {
doFunkyStuffWithFile(cli.file)
}
} catch {
case e: CmdLineException => parser.printUsage(System.err)
}
}
}
In short, you pass an instance of your config class to the parser along with the arguments and the parser automatically parses the input and sets the field values in the config instance. Since the config is a full-fledged Scala class this implies that you get static-type checking for free (in my example above, you pass in a string to the the "-f" argument and args4j knows how to treat the string as a path for the File instance required - same goes for Booleans, Longs etc).
In addition to this you get:
* declarative help/usage printing
* mandatory/optional arguments
* GNU-style long arguments (i.e. --help as an alias for -h)
* multi-valued options
* The ability to plugin your own exotic types for parsing the input strings into.
And yes, Russ, if you wish you can use your unconventional "arg=value" style with args4j as well (though it will not support the commas between the arguments - they are redundant anyway).
Another option (hah!) I heard of recently is JewelCli [2] - this is probably even cleaner to use with Scala since it uses the same annotation-driven declarative approach but uses an Interface (or a pure Trait in Scala) and so you don't have redundantly declare both a field and a setter like I had to do above with args4j. However, I haven't actually used it to see whether it works with Scala.
[1] https://args4j.dev.java.net/
[2] http://jewelcli.sourceforge.net/usage.html
Regards,
Ishaaq
On 21 March 2010 10:19, Russ Paielli <russ.paielli@gmail.com> wrote:
You setup a configuration class declaratively like so:
import org.kohsuke.args4j._
class Cli {
var file: File = null
@Option{val name = "-f", val usage = "The input file to process"}
def setFile(file: File) = this.file = file
var help: Boolean = false
@Option{val name = "-h", val usage = "Displays usage help"}
def setHelp(help: Boolean) = this.help = help
}
(Having to explicitly declare the extra "setter" defs instead of using Scala's handy @BeanProperty is an unfortunate necessity due to the way args4j processes the annotations)
You can then use it like so:
object MyApp {
def main (args: Array[String]) : Unit = {
val cli = new Cli
val parser = new CmdLineParser(cli)
try {
parser.parseArgument(args)
if(cli.help) {
parser.printUsage(System.out)
}else {
doFunkyStuffWithFile(cli.file)
}
} catch {
case e: CmdLineException => parser.printUsage(System.err)
}
}
}
In short, you pass an instance of your config class to the parser along with the arguments and the parser automatically parses the input and sets the field values in the config instance. Since the config is a full-fledged Scala class this implies that you get static-type checking for free (in my example above, you pass in a string to the the "-f" argument and args4j knows how to treat the string as a path for the File instance required - same goes for Booleans, Longs etc).
In addition to this you get:
* declarative help/usage printing
* mandatory/optional arguments
* GNU-style long arguments (i.e. --help as an alias for -h)
* multi-valued options
* The ability to plugin your own exotic types for parsing the input strings into.
And yes, Russ, if you wish you can use your unconventional "arg=value" style with args4j as well (though it will not support the commas between the arguments - they are redundant anyway).
Another option (hah!) I heard of recently is JewelCli [2] - this is probably even cleaner to use with Scala since it uses the same annotation-driven declarative approach but uses an Interface (or a pure Trait in Scala) and so you don't have redundantly declare both a field and a setter like I had to do above with args4j. However, I haven't actually used it to see whether it works with Scala.
[1] https://args4j.dev.java.net/
[2] http://jewelcli.sourceforge.net/usage.html
Regards,
Ishaaq
On 21 March 2010 10:19, Russ Paielli <russ.paielli@gmail.com> wrote:
On Sat, Mar 20, 2010 at 3:43 PM, Randall R Schulz <rschulz@sonic.net> wrote:On Saturday March 20 2010, Russ Paielli wrote:
> On Thu, Mar 18, 2010 at 11:05 AM, Russ Paielli wrote:
> > The "-command" notation originated with low-level scripting
> > languages such as bash, and it makes sense there, but I think we
> > can do better for high-level languages such as Scala. Ultimately it
> > boils down to personal preference, but I have difficulty
> > understanding how anyone could actually prefer the "-command"
> > notation to what I proposed for any reason other than that they are
> > more familiar with it. If we never changed any conventions that we
> > are familiar with, we'd still be using FORTRAN.
Aren't we talking about the command-invocation processing for programs
that just happen to be written in our current all-time-favorite
language, Scala?
Yes.
As far as preference and familiarity: De gustibus non est disputandum.
Bit don't bad-mouth FORTRAN. It had to walk 5 miles to and from school,
uphill both ways in a blizzard every day, 6 days a week, 48 weeks each
year.
I understand that Fortran is still used for heavy-duty number crunching, as in finite-element analysis and such. At least it was a few years ago. But it does have its limitations outside of that arena, of course. I have a colleague in his 70's who is a wiz at numerical analysis and algorithms, but I don't think he understands why we aren't all still using Fortran.
> > Having said that, I really don't care if others adopt my idea or
> > not. If you like it, use it. If not, don't. I like it, and I see no
> > reason not to use it myself, so I will.
>
> Well, maybe I do care a little bit. I added a little feature so that
> you can write "sb=t" as shorthand for "sb=true" (I like to avoid line
> wraps if possible). That's only one character longer than "-sb". I
> also corrected a minor bug so that options set on the command line
> are correctly checked for validity. Here's the new version of
> CommandLine.scala:
This notation is even older and goes back to one of the IBM systems,
JCL, I think. It has to my knowledge exactly one representative in the
Unix / Linux world: The "dd" command.
For what little it's worth, I think this is a reasonable model. In fact,
when I wrote my own command-line parser, I included support for this
kind of option as well as the POSIX "getopt" style. Any given command
definition may include either or both these styles.
Yes, the "getopt" style is perfectly suitable for certain kinds of applications. The main reason I wrote my own parser is that it seemed easier and more fun than figuring out how to use the available alternatives.
I found that the commas simplify parsing, and they also mimic the familiar syntax of arguments passed to a method.
> ... For example, a program could be invoked with the command line
>
> myProgram x=123, 22, zz = blah, 43.5, y=t, gg, rr=3.445
I do not favor the use of commas to separate arguments.
Russ P.
Sun, 2010-03-21, 14:27
#11
Re: Re: parsing command-line options and arguments
I cut my eye teeth on FORTRAN and on systems that supported command line
syntax like the following:
COMMAND,OPT1=FOO,OPT2=BAR/LO=F
(Yeah, I have my share of grey in my beard.)
I vastly prefer the Unix-style option syntax for most things, for three very
simple reasons:
- White space is eminently more readable than an embedded "=".
- I have to do less typing (no Shift for the "=", no unnecessary ","
characters) than with the Unix-style syntax.
- The space bar is really, really big. It's hard to miss.
My advice (which, of course, you are completely free to ignore): If you're
writing tools for humans to invoke at a command line, be sure to support
at least one syntax that's easier to type.
Also, if you're going for a method-passing syntax, why not go all the way,
and insist on parentheses? ;-)
Sun, 2010-03-21, 19:57
#12
Re: Re: parsing command-line options and arguments
On Sun, Mar 21, 2010 at 6:20 AM, Brian Clapper <bmc@clapper.org> wrote:
I can't blame you for disliking that. Without whitespace, it is not easy for a human to understand. If whitespace is not allowed, that's no good. My approach allows all the whitespace you want, including around the "=".
You can use the space bar all you want with my approach.
For mass-market software that will be used by thousands of people, you are probably right. I tend to write software that is used only by myself and a few others, so I don't need to worry much about that. Also, when I run a program many times, I often embed the command line in a bash script that runs more than one program. (Or I type it once at the bash prompt, then use !! to repeat the command over and over for testing.) In most cases, I don't repeatedly type the command line, so typing is not a big issue for me.
Well, *requiring* parenthesis would be silly, but I did consider *allowing* them. It would be very easy to do.
Russ P.
I cut my eye teeth on FORTRAN and on systems that supported command line
syntax like the following:
COMMAND,OPT1=FOO,OPT2=BAR/LO=F
I can't blame you for disliking that. Without whitespace, it is not easy for a human to understand. If whitespace is not allowed, that's no good. My approach allows all the whitespace you want, including around the "=".
(Yeah, I have my share of grey in my beard.)
I vastly prefer the Unix-style option syntax for most things, for three very
simple reasons:
- White space is eminently more readable than an embedded "=".
- I have to do less typing (no Shift for the "=", no unnecessary ","
characters) than with the Unix-style syntax.
- The space bar is really, really big. It's hard to miss.
You can use the space bar all you want with my approach.
My advice (which, of course, you are completely free to ignore): If you're
writing tools for humans to invoke at a command line, be sure to support
at least one syntax that's easier to type.
For mass-market software that will be used by thousands of people, you are probably right. I tend to write software that is used only by myself and a few others, so I don't need to worry much about that. Also, when I run a program many times, I often embed the command line in a bash script that runs more than one program. (Or I type it once at the bash prompt, then use !! to repeat the command over and over for testing.) In most cases, I don't repeatedly type the command line, so typing is not a big issue for me.
Also, if you're going for a method-passing syntax, why not go all the way,
and insist on parentheses? ;-)
Well, *requiring* parenthesis would be silly, but I did consider *allowing* them. It would be very easy to do.
Russ P.
Mon, 2010-03-22, 02:57
#13
Re: Re: parsing command-line options and arguments
How is requiring redundant parenthesis any more silly than requiring redundant commas?
On 22 March 2010 05:56, Russ Paielli <russ.paielli@gmail.com> wrote:
On 22 March 2010 05:56, Russ Paielli <russ.paielli@gmail.com> wrote:
Also, if you're going for a method-passing syntax, why not go all the way,
and insist on parentheses? ;-)
Well, *requiring* parenthesis would be silly, but I did consider *allowing* them. It would be very easy to do.
Russ P.
Mon, 2010-03-22, 04:47
#14
Re: Re: parsing command-line options and arguments
The commas enhance readability and simplify the parsing of the command line.
Aren't commas redundant in method definitions and calls? Should we eliminate them there too?
On Sun, Mar 21, 2010 at 6:47 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
--
http://RussP.us
Aren't commas redundant in method definitions and calls? Should we eliminate them there too?
On Sun, Mar 21, 2010 at 6:47 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
How is requiring redundant parenthesis any more silly than requiring redundant commas?
On 22 March 2010 05:56, Russ Paielli <russ.paielli@gmail.com> wrote:
Also, if you're going for a method-passing syntax, why not go all the way,
and insist on parentheses? ;-)
Well, *requiring* parenthesis would be silly, but I did consider *allowing* them. It would be very easy to do.
Russ P.
--
http://RussP.us
Mon, 2010-03-22, 17:47
#15
RE: Re: parsing command-line options and arguments
BTW, the excellent paulp has already made something approaching, and as always, pretty cool, see: http://github.com/paulp/optional#readme
Gilles.
From: Russ Paielli
[mailto:russ.paielli@gmail.com]
Sent: lundi 22 mars 2010 4:46
To: scala-user
Subject: Re: [scala-user] Re: parsing command-line options and arguments
The commas enhance readability
and simplify the parsing of the command line.
Aren't commas redundant in method definitions and calls? Should we eliminate
them there too?
On Sun, Mar 21, 2010 at 6:47 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
How is requiring redundant parenthesis any more silly than requiring redundant commas?
On 22 March 2010 05:56, Russ Paielli <russ.paielli@gmail.com> wrote:
Also, if you're going for a method-passing syntax, why not go all the way,
and insist on parentheses? ;-)
Well, *requiring* parenthesis would be silly, but I did consider *allowing*
them. It would be very easy to do.
Russ P.
Mon, 2010-03-22, 19:17
#16
Returning class of type Class[T] from classname
I have a class parameterized by type T and I'd like to have a method
that returns Class[T] where the String name of the class or
subclass is a method argument:
class MyClass[T] {
def convert(value: String): Class[T] = {
val c = Class.forName(value)
c
}
}
> scalac MyClass.scala
MyClass.scala:5: error: type mismatch;
found : java.lang.Class[?0] where type ?0
required: Class[T]
c
^
one error found
In Java one might do the following:
public Class<? extends T> convert(String v) {
try {
Class cls = Class.forName(v);
return (Class<? extends T>) cls;
} catch (ClassNotFoundException ex) {
final String msg = "ClassProperty.convert: " +
"could not find class with name: \""+
v +
"\""
;
log.warn(msg);
return null;
}
}
How does one do this in Scala?
Thanks
Richard
Mon, 2010-03-22, 19:27
#17
Re: Returning class of type Class[T] from classname
On Mon, Mar 22, 2010 at 11:14 AM, richard emberson <richard.emberson@gmail.com> wrote:
I have a class parameterized by type T and I'd like to have a method
that returns Class[T] where the String name of the class or
subclass is a method argument:
class MyClass[T] {
def convert(value: String): Class[T] = {
val c = Class.forName(value)
c
}
}
> scalac MyClass.scala
MyClass.scala:5: error: type mismatch;
found : java.lang.Class[?0] where type ?0
required: Class[T]
c
^
one error found
You could do:
def convert[T](clzName: String): Class[T] = Class.forName(clzName).asInstanceOf[Class[T]]
But it's not type safe. There's no way to insure that T is correct because you're just converting a String.
When do you need Class[T] rather than Class[_]?
In Java one might do the following:
public Class<? extends T> convert(String v) {
try {
Class cls = Class.forName(v);
return (Class<? extends T>) cls;
} catch (ClassNotFoundException ex) {
final String msg = "ClassProperty.convert: " +
"could not find class with name: \""+
v +
"\""
;
log.warn(msg);
return null;
}
}
How does one do this in Scala?
Thanks
Richard
Mon, 2010-03-22, 19:37
#18
Re: Returning class of type Class[T] from classname
While the syntax is different, you can do exactly the same thing as in Java
class MyClass[T] { def convert(value: String): Class[_ <: T] = Class.forName(value).asInstanceOf[Class[_ <: T]] }
Of course that suffers from the same problems as in Java. Namely there's no static proof that the string "value" and T have anything to do with each other and, due to type erasure, the dynamic check cannot be performed at the point of casting but must be delayed until (possibly much) later.
scala> val x = new MyClass[Int] x: MyClass[Int] = MyClass@9cc3baa
scala> val clazz = x.convert("java.lang.String")clazz: java.lang.Class[_ <: Int] = class java.lang.String
See, no errors! Until...
scala> clazz.newInstance() java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
On Mon, Mar 22, 2010 at 11:14 AM, richard emberson <richard.emberson@gmail.com> wrote:
class MyClass[T] { def convert(value: String): Class[_ <: T] = Class.forName(value).asInstanceOf[Class[_ <: T]] }
Of course that suffers from the same problems as in Java. Namely there's no static proof that the string "value" and T have anything to do with each other and, due to type erasure, the dynamic check cannot be performed at the point of casting but must be delayed until (possibly much) later.
scala> val x = new MyClass[Int] x: MyClass[Int] = MyClass@9cc3baa
scala> val clazz = x.convert("java.lang.String")clazz: java.lang.Class[_ <: Int] = class java.lang.String
See, no errors! Until...
scala> clazz.newInstance() java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
On Mon, Mar 22, 2010 at 11:14 AM, richard emberson <richard.emberson@gmail.com> wrote:
I have a class parameterized by type T and I'd like to have a method
that returns Class[T] where the String name of the class or
subclass is a method argument:
class MyClass[T] {
def convert(value: String): Class[T] = {
val c = Class.forName(value)
c
}
}
> scalac MyClass.scala
MyClass.scala:5: error: type mismatch;
found : java.lang.Class[?0] where type ?0
required: Class[T]
c
^
one error found
In Java one might do the following:
public Class<? extends T> convert(String v) {
try {
Class cls = Class.forName(v);
return (Class<? extends T>) cls;
} catch (ClassNotFoundException ex) {
final String msg = "ClassProperty.convert: " +
"could not find class with name: \""+
v +
"\""
;
log.warn(msg);
return null;
}
}
How does one do this in Scala?
Thanks
Richard
Mon, 2010-03-22, 20:57
#19
Enumeration Values from Value
Given an Enumeration Value, can one get to its sibling values?
object Visibility extends Enumeration {
type Visibility = Value
val EXTERNAL, INTERNAL, BOTH = Value
}
def foo(value: T <: Enumeration) {
val allValues: Set[T#Value] = ????
for (v <- allValues) print(v.toString)
}
// iterator over all possible values of the Visibility Enumeration
foo(Visibility.BOTH)
In Java, given an Enum value one can get its class and, from the
class, all of the values of that particular Enum (using
Enum.valueOf(cls, v)). How can I do something similar in Scala?
Thanks
Richard
Mon, 2010-03-22, 23:47
#20
Re: Re: parsing command-line options and arguments
No, commas in method definitions and calls are NOT redundant in a lot of languages (Scala being one of them). And yes, some languages do eliminate commas in method definitions and calls. It would depend on the syntax of the language whether you could eliminate them without ambiguity.
However, in your command line args syntax they ARE redundant and serve no functional purpose. So, since you are supposedly emulating C-style method call syntax, why not go the whole hog and require parenthesis as well? Like commas, they are required (not redundant) by Java and for most Scala method definitions and calls. Doing this is no more "silly" (your word, not mine) than requiring redundant commas.
And to a lesser argument (simply because it is my subjective opinion); no, the commas do not enhance readability in the command line args context - whitespace is easy enough for my eyes to parse.
On 22 March 2010 14:46, Russ Paielli <russ.paielli@gmail.com> wrote:
However, in your command line args syntax they ARE redundant and serve no functional purpose. So, since you are supposedly emulating C-style method call syntax, why not go the whole hog and require parenthesis as well? Like commas, they are required (not redundant) by Java and for most Scala method definitions and calls. Doing this is no more "silly" (your word, not mine) than requiring redundant commas.
And to a lesser argument (simply because it is my subjective opinion); no, the commas do not enhance readability in the command line args context - whitespace is easy enough for my eyes to parse.
On 22 March 2010 14:46, Russ Paielli <russ.paielli@gmail.com> wrote:
The commas enhance readability and simplify the parsing of the command line.
Aren't commas redundant in method definitions and calls? Should we eliminate them there too?
On Sun, Mar 21, 2010 at 6:47 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
How is requiring redundant parenthesis any more silly than requiring redundant commas?
On 22 March 2010 05:56, Russ Paielli <russ.paielli@gmail.com> wrote:
Also, if you're going for a method-passing syntax, why not go all the way,
and insist on parentheses? ;-)
Well, *requiring* parenthesis would be silly, but I did consider *allowing* them. It would be very easy to do.
Russ P.
--
http://RussP.us
Mon, 2010-03-22, 23:57
#21
Re: Re: parsing command-line options and arguments
Awesome! Its only missing the ability to print usage help, but that is less important than going one step further and eliminating arg4j's need for declarative annotations and moving them in as method args instead and still retain static typing. Nice.
I especially like the use of Option to denote optional arguments.
On 23 March 2010 03:40, Gilles SCOUVART <Gilles.SCOUVART@n-side.be> wrote:
I especially like the use of Option to denote optional arguments.
On 23 March 2010 03:40, Gilles SCOUVART <Gilles.SCOUVART@n-side.be> wrote:
BTW, the excellent paulp has already made something approaching, and as always, pretty cool, see: http://github.com/paulp/optional#readme
Gilles.
Tue, 2010-03-23, 00:17
#22
Re: Re: parsing command-line options and arguments
I find this:
x= 123, 22, zz = blah, 43.5, y =true , gg, rr=3.445
easier to read than this:
x= 123 22 zz = blah 43.5 y =true gg rr=3.445
Since you are so concerned about redundancy, why don't you eliminate all the redundant line feeds from all your Scala source code, and let us know how you like the result. While you're at it, why don't you also shorten all your identifiers to one character, since all the additional characters are redundant (until you run out of letters, that is).
I actually consider myself an "obsessive minimalist. I often spend more time than I should trying to get my code as simple and succinct as possible, but only in the service of readability -- never at the expense of readability.
As I said before, the commas also simplify parsing. Since I'm doing the parsing myself, I'll just keep them. If nobody else wants to use them (or my code for parsing them), then so be it.
Russ P.
On Mon, Mar 22, 2010 at 3:41 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
--
http://RussP.us
x= 123, 22, zz = blah, 43.5, y =true , gg, rr=3.445
easier to read than this:
x= 123 22 zz = blah 43.5 y =true gg rr=3.445
Since you are so concerned about redundancy, why don't you eliminate all the redundant line feeds from all your Scala source code, and let us know how you like the result. While you're at it, why don't you also shorten all your identifiers to one character, since all the additional characters are redundant (until you run out of letters, that is).
I actually consider myself an "obsessive minimalist. I often spend more time than I should trying to get my code as simple and succinct as possible, but only in the service of readability -- never at the expense of readability.
As I said before, the commas also simplify parsing. Since I'm doing the parsing myself, I'll just keep them. If nobody else wants to use them (or my code for parsing them), then so be it.
Russ P.
On Mon, Mar 22, 2010 at 3:41 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
No, commas in method definitions and calls are NOT redundant in a lot of languages (Scala being one of them). And yes, some languages do eliminate commas in method definitions and calls. It would depend on the syntax of the language whether you could eliminate them without ambiguity.
However, in your command line args syntax they ARE redundant and serve no functional purpose. So, since you are supposedly emulating C-style method call syntax, why not go the whole hog and require parenthesis as well? Like commas, they are required (not redundant) by Java and for most Scala method definitions and calls. Doing this is no more "silly" (your word, not mine) than requiring redundant commas.
And to a lesser argument (simply because it is my subjective opinion); no, the commas do not enhance readability in the command line args context - whitespace is easy enough for my eyes to parse.
On 22 March 2010 14:46, Russ Paielli <russ.paielli@gmail.com> wrote:
The commas enhance readability and simplify the parsing of the command line.
Aren't commas redundant in method definitions and calls? Should we eliminate them there too?
On Sun, Mar 21, 2010 at 6:47 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
How is requiring redundant parenthesis any more silly than requiring redundant commas?
On 22 March 2010 05:56, Russ Paielli <russ.paielli@gmail.com> wrote:
Also, if you're going for a method-passing syntax, why not go all the way,
and insist on parentheses? ;-)
Well, *requiring* parenthesis would be silly, but I did consider *allowing* them. It would be very easy to do.
Russ P.
--
http://RussP.us
--
http://RussP.us
Tue, 2010-03-23, 00:27
#23
Re: Returning class of type Class[T] from classname
Consider this question and its answers:
http://stackoverflow.com/questions/2433575/generic-object-load-function-for-scala/2434743
On Mon, Mar 22, 2010 at 3:14 PM, richard emberson <richard.emberson@gmail.com> wrote:
http://stackoverflow.com/questions/2433575/generic-object-load-function-for-scala/2434743
On Mon, Mar 22, 2010 at 3:14 PM, richard emberson <richard.emberson@gmail.com> wrote:
I have a class parameterized by type T and I'd like to have a method
that returns Class[T] where the String name of the class or
subclass is a method argument:
class MyClass[T] {
def convert(value: String): Class[T] = {
val c = Class.forName(value)
c
}
}
> scalac MyClass.scala
MyClass.scala:5: error: type mismatch;
found : java.lang.Class[?0] where type ?0
required: Class[T]
c
^
one error found
In Java one might do the following:
public Class<? extends T> convert(String v) {
try {
Class cls = Class.forName(v);
return (Class<? extends T>) cls;
} catch (ClassNotFoundException ex) {
final String msg = "ClassProperty.convert: " +
"could not find class with name: \""+
v +
"\""
;
log.warn(msg);
return null;
}
}
How does one do this in Scala?
Thanks
Richard
Tue, 2010-03-23, 00:57
#24
Re: Re: parsing command-line options and arguments
I took a look at paulp's command-line parser before I wrote my own. I may be nit-picking here, but one thing bothered me. Consider this example of its usage:
In my CommandLine class (posted earlier in this thread), only one name is needed:
def main(args: Array[String]) {
val com = new CommandLine(args)
val greeting = com.str("greeting", "Hello!") // "Hello!" is the default
No offense to paulp -- he can probably code circles around me in general. Also his approach supports conventional -command style options, and mine doesn't.
Russ P.
On Mon, Mar 22, 2010 at 3:50 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
--
http://RussP.us
def main(times: Option[Int], greeting: Option[String], file: java.io.File) {Here you see that a second name is apparently needed for each variable, such as "greeting" and "_greeting."
val _greeting = greeting getOrElse "hello"
val _times = times getOrElse 1
In my CommandLine class (posted earlier in this thread), only one name is needed:
def main(args: Array[String]) {
val com = new CommandLine(args)
val greeting = com.str("greeting", "Hello!") // "Hello!" is the default
No offense to paulp -- he can probably code circles around me in general. Also his approach supports conventional -command style options, and mine doesn't.
Russ P.
On Mon, Mar 22, 2010 at 3:50 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
Awesome! Its only missing the ability to print usage help, but that is less important than going one step further and eliminating arg4j's need for declarative annotations and moving them in as method args instead and still retain static typing. Nice.
I especially like the use of Option to denote optional arguments.
On 23 March 2010 03:40, Gilles SCOUVART <Gilles.SCOUVART@n-side.be> wrote:
BTW, the excellent paulp has already made something approaching, and as always, pretty cool, see: http://github.com/paulp/optional#readme
Gilles.
--
http://RussP.us
Tue, 2010-03-23, 01:17
#25
Re: Re: parsing command-line options and arguments
The problem with using programming language analogies in this context is the vast difference in the complexity of parsing command-line args to parsing a full-fledged language - surely you see that?
Apologies, I did not realise you wanted multi-valued args (by the way, they break your emulate-method-calls-design). For them, I would possibly use commas like so:
-x 123,22 -zz blah,43.5 -y true,gg -rr 3.445
or, if you insist:
x=123,22 zz=blah,43.5 y=true,gg rr=3.445
This would ensure that the more common use case of single-valued options is still quick to type and easy to read.
As for your parsing-simplicity argument - well, I don't see how parsing a comma is any more or less easy than parsing whitespace.
I do agree with you on one thing though - if it works for you, and you are the only one using it, no one can really argue with you on that. Following conventions only comes into its own when collaborating with others. Most of my code is used and read by others which is why I'd rather more conventional approaches to command-line parsing - especially when there are a good selection of libraries available to not require rolling your own implementation.
Ishaaq
On 23 March 2010 10:13, Russ Paielli <russ.paielli@gmail.com> wrote:
Apologies, I did not realise you wanted multi-valued args (by the way, they break your emulate-method-calls-design). For them, I would possibly use commas like so:
-x 123,22 -zz blah,43.5 -y true,gg -rr 3.445
or, if you insist:
x=123,22 zz=blah,43.5 y=true,gg rr=3.445
This would ensure that the more common use case of single-valued options is still quick to type and easy to read.
As for your parsing-simplicity argument - well, I don't see how parsing a comma is any more or less easy than parsing whitespace.
I do agree with you on one thing though - if it works for you, and you are the only one using it, no one can really argue with you on that. Following conventions only comes into its own when collaborating with others. Most of my code is used and read by others which is why I'd rather more conventional approaches to command-line parsing - especially when there are a good selection of libraries available to not require rolling your own implementation.
Ishaaq
On 23 March 2010 10:13, Russ Paielli <russ.paielli@gmail.com> wrote:
I find this:
x= 123, 22, zz = blah, 43.5, y =true , gg, rr=3.445
easier to read than this:
x= 123 22 zz = blah 43.5 y =true gg rr=3.445
Since you are so concerned about redundancy, why don't you eliminate all the redundant line feeds from all your Scala source code, and let us know how you like the result. While you're at it, why don't you also shorten all your identifiers to one character, since all the additional characters are redundant (until you run out of letters, that is).
I actually consider myself an "obsessive minimalist. I often spend more time than I should trying to get my code as simple and succinct as possible, but only in the service of readability -- never at the expense of readability.
As I said before, the commas also simplify parsing. Since I'm doing the parsing myself, I'll just keep them. If nobody else wants to use them (or my code for parsing them), then so be it.
Russ P.
On Mon, Mar 22, 2010 at 3:41 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:No, commas in method definitions and calls are NOT redundant in a lot of languages (Scala being one of them). And yes, some languages do eliminate commas in method definitions and calls. It would depend on the syntax of the language whether you could eliminate them without ambiguity.
However, in your command line args syntax they ARE redundant and serve no functional purpose. So, since you are supposedly emulating C-style method call syntax, why not go the whole hog and require parenthesis as well? Like commas, they are required (not redundant) by Java and for most Scala method definitions and calls. Doing this is no more "silly" (your word, not mine) than requiring redundant commas.
And to a lesser argument (simply because it is my subjective opinion); no, the commas do not enhance readability in the command line args context - whitespace is easy enough for my eyes to parse.
On 22 March 2010 14:46, Russ Paielli <russ.paielli@gmail.com> wrote:
The commas enhance readability and simplify the parsing of the command line.
Aren't commas redundant in method definitions and calls? Should we eliminate them there too?
On Sun, Mar 21, 2010 at 6:47 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
How is requiring redundant parenthesis any more silly than requiring redundant commas?
On 22 March 2010 05:56, Russ Paielli <russ.paielli@gmail.com> wrote:
Also, if you're going for a method-passing syntax, why not go all the way,
and insist on parentheses? ;-)
Well, *requiring* parenthesis would be silly, but I did consider *allowing* them. It would be very easy to do.
Russ P.
--
http://RussP.us
--
http://RussP.us
Tue, 2010-03-23, 01:27
#26
Re: Re: parsing command-line options and arguments
Hmm, I didn't think it was that much of a big deal, but I wonder if you could solve it using annotations, i.e. something like this:
Ishaaq
On 23 March 2010 10:55, Russ Paielli <russ.paielli@gmail.com> wrote:
def main(@Optional("10") times: Int, @Optional("default") greeting: String, file: java.io.File)Where @Optional would be a custom annotation that the library knows to read and apply if no value is available in the argument list. hmm, food for thought.
Ishaaq
On 23 March 2010 10:55, Russ Paielli <russ.paielli@gmail.com> wrote:
I took a look at paulp's command-line parser before I wrote my own. I may be nit-picking here, but one thing bothered me. Consider this example of its usage:
def main(times: Option[Int], greeting: Option[String], file: java.io.File) {Here you see that a second name is apparently needed for each variable, such as "greeting" and "_greeting."
val _greeting = greeting getOrElse "hello"
val _times = times getOrElse 1
In my CommandLine class (posted earlier in this thread), only one name is needed:
def main(args: Array[String]) {
val com = new CommandLine(args)
val greeting = com.str("greeting", "Hello!") // "Hello!" is the default
No offense to paulp -- he can probably code circles around me in general. Also his approach supports conventional -command style options, and mine doesn't.
Russ P.
On Mon, Mar 22, 2010 at 3:50 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
Awesome! Its only missing the ability to print usage help, but that is less important than going one step further and eliminating arg4j's need for declarative annotations and moving them in as method args instead and still retain static typing. Nice.
I especially like the use of Option to denote optional arguments.
On 23 March 2010 03:40, Gilles SCOUVART <Gilles.SCOUVART@n-side.be> wrote:
BTW, the excellent paulp has already made something approaching, and as always, pretty cool, see: http://github.com/paulp/optional#readme
Gilles.
--
http://RussP.us
Tue, 2010-03-23, 01:37
#27
Re: Re: parsing command-line options and arguments
On Mon, Mar 22, 2010 at 5:13 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
I didn't say anything about multi-valued arguments. I think you misunderstood something somewhere.
In my approach, there is always one and only one comma between fields on the command line. The same does not apply to whitespace, so parsing becomes more complicated. Here's my parsing code:
private def initialize(line: Array[String]): Int = {
for (field <- line.mkString(" ").split(",")) {
if (field.contains("=")) { // assignment-style argument
val pair = field.split("=")
val key = pair(0).trim
val value = pair(1).trim
checkOption(key)
map(key) = value
}
else args.append(field.trim) // regular (non-assignment) arguments
}
args.length // number of regular (non-assignment) arguments
}
The problem with using programming language analogies in this context is the vast difference in the complexity of parsing command-line args to parsing a full-fledged language - surely you see that?
Apologies, I did not realise you wanted multi-valued args (by the way, they break your emulate-method-calls-design). For them, I would possibly use commas like so:
-x 123,22 -zz blah,43.5 -y true,gg -rr 3.445
I didn't say anything about multi-valued arguments. I think you misunderstood something somewhere.
or, if you insist:
x=123,22 zz=blah,43.5 y=true,gg rr=3.445
This would ensure that the more common use case of single-valued options is still quick to type and easy to read.
As for your parsing-simplicity argument - well, I don't see how parsing a comma is any more or less easy than parsing whitespace.
In my approach, there is always one and only one comma between fields on the command line. The same does not apply to whitespace, so parsing becomes more complicated. Here's my parsing code:
private def initialize(line: Array[String]): Int = {
for (field <- line.mkString(" ").split(",")) {
if (field.contains("=")) { // assignment-style argument
val pair = field.split("=")
val key = pair(0).trim
val value = pair(1).trim
checkOption(key)
map(key) = value
}
else args.append(field.trim) // regular (non-assignment) arguments
}
args.length // number of regular (non-assignment) arguments
}
Tue, 2010-03-23, 02:47
#28
Re: Re: parsing command-line options and arguments
On 23 March 2010 11:25, Russ Paielli <russ.paielli@gmail.com> wrote:
So what did you mean when you gave the following example?
I didn't say anything about multi-valued arguments. I think you misunderstood something somewhere.
x= 123, 22, zz = blah, 43.5, y =true , gg, rr=3.445
What is the value of the x argument, if it is not a multi-valued argument with two values: 123 and 22?
In my approach, there is always one and only one comma between fields on the command line. The same does not apply to whitespace, so parsing becomes more complicated. Here's my parsing code:
In your code replace:
for (field <- line.mkString(" ").split(",")) {
with:
for (field <- line.mkString(" ").split("\\s+")
The string argument to the split method is actually a regex pattern, even in the simple form you were using. Not that much more complicated, is it?
Ishaaq
Tue, 2010-03-23, 03:27
#29
Re: Re: parsing command-line options and arguments
So what did you mean when you gave the following example?x = 123, an integer. The "22" is the first "regular" (i.e., non-assignment-style) argument. As I said, the commas delimit the fields of the command line.
x= 123, 22, zz = blah, 43.5, y =true , gg, rr=3.445
What is the value of the x argument, if it is not a multi-valued argument with two values: 123 and 22?
No, it isn't. I'm sure it wouldn't be much more complicated to implement conventional -command (or --command) style arguments using my approach. I just don't need it for my own purposes right now. But maybe I will someday.
In my approach, there is always one and only one comma between fields on the command line. The same does not apply to whitespace, so parsing becomes more complicated. Here's my parsing code:
In your code replace:for (field <- line.mkString(" ").split(",")) {
with:
for (field <- line.mkString(" ").split("\\s+")
The string argument to the split method is actually a regex pattern, even in the simple form you were using. Not that much more complicated, is it?
Russ P.
Tue, 2010-03-23, 05:37
#30
Re: Re: parsing command-line options and arguments
With the new named and default arguments syntax in 2.8, I think that would be a better approach than an annotation.
--j
On Mon, Mar 22, 2010 at 5:19 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
--j
On Mon, Mar 22, 2010 at 5:19 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
Hmm, I didn't think it was that much of a big deal, but I wonder if you could solve it using annotations, i.e. something like this:
def main(@Optional("10") times: Int, @Optional("default") greeting: String, file: java.io.File)Where @Optional would be a custom annotation that the library knows to read and apply if no value is available in the argument list. hmm, food for thought.
Ishaaq
On 23 March 2010 10:55, Russ Paielli <russ.paielli@gmail.com> wrote:
I took a look at paulp's command-line parser before I wrote my own. I may be nit-picking here, but one thing bothered me. Consider this example of its usage:
def main(times: Option[Int], greeting: Option[String], file: java.io.File) {Here you see that a second name is apparently needed for each variable, such as "greeting" and "_greeting."
val _greeting = greeting getOrElse "hello"
val _times = times getOrElse 1
In my CommandLine class (posted earlier in this thread), only one name is needed:
def main(args: Array[String]) {
val com = new CommandLine(args)
val greeting = com.str("greeting", "Hello!") // "Hello!" is the default
No offense to paulp -- he can probably code circles around me in general. Also his approach supports conventional -command style options, and mine doesn't.
Russ P.
On Mon, Mar 22, 2010 at 3:50 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
Awesome! Its only missing the ability to print usage help, but that is less important than going one step further and eliminating arg4j's need for declarative annotations and moving them in as method args instead and still retain static typing. Nice.
I especially like the use of Option to denote optional arguments.
On 23 March 2010 03:40, Gilles SCOUVART <Gilles.SCOUVART@n-side.be> wrote:
BTW, the excellent paulp has already made something approaching, and as always, pretty cool, see: http://github.com/paulp/optional#readme
Gilles.
--
http://RussP.us
Tue, 2010-03-23, 06:57
#31
Re: Re: parsing command-line options and arguments
I don't think named args are going to be of much use in this context but possibly default args would, though it would depend on whether or not the defaults are available via reflection at runtime - because that is what the "optional" library uses to do its magic.
I highly doubt it though, because reflection is done using Java semantics - where default values are not available. The scala compiler must be achieving this at compile time at the call-site - useless for run-time reflection access. But because I know nothing of how the scala compiler achieves this I could be wrong.
Ishaaq
On 23 March 2010 15:27, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
I highly doubt it though, because reflection is done using Java semantics - where default values are not available. The scala compiler must be achieving this at compile time at the call-site - useless for run-time reflection access. But because I know nothing of how the scala compiler achieves this I could be wrong.
Ishaaq
On 23 March 2010 15:27, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
With the new named and default arguments syntax in 2.8, I think that would be a better approach than an annotation.
--j
On Mon, Mar 22, 2010 at 5:19 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
Hmm, I didn't think it was that much of a big deal, but I wonder if you could solve it using annotations, i.e. something like this:
def main(@Optional("10") times: Int, @Optional("default") greeting: String, file: java.io.File)Where @Optional would be a custom annotation that the library knows to read and apply if no value is available in the argument list. hmm, food for thought.
Ishaaq
On 23 March 2010 10:55, Russ Paielli <russ.paielli@gmail.com> wrote:
I took a look at paulp's command-line parser before I wrote my own. I may be nit-picking here, but one thing bothered me. Consider this example of its usage:
def main(times: Option[Int], greeting: Option[String], file: java.io.File) {Here you see that a second name is apparently needed for each variable, such as "greeting" and "_greeting."
val _greeting = greeting getOrElse "hello"
val _times = times getOrElse 1
In my CommandLine class (posted earlier in this thread), only one name is needed:
def main(args: Array[String]) {
val com = new CommandLine(args)
val greeting = com.str("greeting", "Hello!") // "Hello!" is the default
No offense to paulp -- he can probably code circles around me in general. Also his approach supports conventional -command style options, and mine doesn't.
Russ P.
On Mon, Mar 22, 2010 at 3:50 PM, Ishaaq Chandy <ishaaq@gmail.com> wrote:
Awesome! Its only missing the ability to print usage help, but that is less important than going one step further and eliminating arg4j's need for declarative annotations and moving them in as method args instead and still retain static typing. Nice.
I especially like the use of Option to denote optional arguments.
On 23 March 2010 03:40, Gilles SCOUVART <Gilles.SCOUVART@n-side.be> wrote:
BTW, the excellent paulp has already made something approaching, and as always, pretty cool, see: http://github.com/paulp/optional#readme
Gilles.
--
http://RussP.us
Tue, 2010-03-23, 10:27
#32
Re: Enumeration Values from Value
In 2.8 you can use values to obtain the value set and then iterate over it just like any set. See http://www.scala-lang.org/archives/downloads/distrib/files/nightly/docs/library/scala/Enumeration$ValueSet.html for details
2010/3/22 richard emberson <richard.emberson@gmail.com>
2010/3/22 richard emberson <richard.emberson@gmail.com>
Given an Enumeration Value, can one get to its sibling values?
object Visibility extends Enumeration {
type Visibility = Value
val EXTERNAL, INTERNAL, BOTH = Value
}
def foo(value: T <: Enumeration) {
val allValues: Set[T#Value] = ????
for (v <- allValues) print(v.toString)
}
// iterator over all possible values of the Visibility Enumeration
foo(Visibility.BOTH)
In Java, given an Enum value one can get its class and, from the
class, all of the values of that particular Enum (using
Enum.valueOf(cls, v)). How can I do something similar in Scala?
Thanks
Richard
Tue, 2010-03-23, 16:07
#33
Re: Enumeration Values from Value
I believe that access to the value set is via the Visibility object,
not any particular Value instance. So, the problem is
given some Value instance, how to get to its "outer" Enumeration
object instance? The Value's class name does not include
its outer object's name, only the Enumeration.
Thanks
On 03/23/2010 02:17 AM, Stefan Langer wrote:
> In 2.8 you can use values to obtain the value set and then iterate over
> it just like any set. See
> http://www.scala-lang.org/archives/downloads/distrib/files/nightly/docs/library/scala/Enumeration$ValueSet.html
> for details
>
>
> 2010/3/22 richard emberson >
>
> Given an Enumeration Value, can one get to its sibling values?
>
> object Visibility extends Enumeration {
> type Visibility = Value
> val EXTERNAL, INTERNAL, BOTH = Value
> }
>
> def foo(value: T <: Enumeration) {
> val allValues: Set[T#Value] = ????
> for (v <- allValues) print(v.toString)
> }
>
> // iterator over all possible values of the Visibility Enumeration
> foo(Visibility.BOTH)
>
> In Java, given an Enum value one can get its class and, from the
> class, all of the values of that particular Enum (using
> Enum.valueOf(cls, v)). How can I do something similar in Scala?
>
> Thanks
> Richard
> --
> Quis custodiet ipsos custodes
>
>
Wed, 2010-06-02, 17:27
#34
Re: Re: parsing command-line options and arguments
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Russ Paielli schrieb:
>> So what did you mean when you gave the following example?
>>
>> x= 123, 22, zz = blah, 43.5, y =true , gg, rr=3.445
>>
>> What is the value of the x argument, if it is not a multi-valued argument
>> with two values: 123 and 22?
>>
>>
> x = 123, an integer. The "22" is the first "regular" (i.e.,
> non-assignment-style) argument. As I said, the commas delimit the fields of
> the command line.
>
If I understand correctly, the space-delimiter is optional? So that in fact
x= 123, 22, zz = blah, 43.5, y =true , gg, rr=3.445
and
x=123,22,zz=blah,43.5,y=true,gg,rr=3.445
would be allowed and should mean the same thing?
In a german environment (locale=de_DE), the comma is used as
decimal-separator, so I would read it like x=123.22 without blank.
To understand how to use the program I would need to know which kind of
parsing it is using.
In general I don't see any advantage which would be an excuse for
introducing the 4th kind of argument passing.
- --
Tschööö--->...Stefan
- ---------------------------
Don't visit my homepage at:
http://home.arcor-online.net/hirnstrom
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFMBoSTQeATqGpDnRoRAsrYAJsEJX4jl4O4zbCmvh+wy3XM4DVj0QCgowku
lKhHqr2Zoi7oiQ4pEgPxJ7A=
=mEzr
-----END PGP SIGNATURE-----
Wed, 2010-06-02, 19:07
#35
Re: Re: parsing command-line options and arguments
On Wed, Jun 2, 2010 at 9:19 AM, Stefan Wagner <wagner.stefan@berlin.de> wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Russ Paielli schrieb:
>> So what did you mean when you gave the following example?
>>
>> x= 123, 22, zz = blah, 43.5, y =true , gg, rr=3.445
>>
>> What is the value of the x argument, if it is not a multi-valued argument
>> with two values: 123 and 22?
>>
>>
> x = 123, an integer. The "22" is the first "regular" (i.e.,
> non-assignment-style) argument. As I said, the commas delimit the fields of
> the command line.
>
If I understand correctly, the space-delimiter is optional? So that in fact
x= 123, 22, zz = blah, 43.5, y =true , gg, rr=3.445
and
x=123,22,zz=blah,43.5,y=true,gg,rr=3.445
would be allowed and should mean the same thing?
Yes, it would be allowed, and it would mean the same thing, but there would be no good reason to write it that way.
In a german environment (locale=de_DE), the comma is used as
decimal-separator, so I would read it like x=123.22 without blank.
You could say the same thing about normal argument passing in Scala (or almost any other language as well). I don't think you want to change that.
To understand how to use the program I would need to know which kind of
parsing it is using.
In general I don't see any advantage which would be an excuse for
introducing the 4th kind of argument passing.
Fair enough. If you don't like it, don't use it. It suits my purposes well, so I will continue to use it.
By the way, there was a bug in my earlier post of the code for this. It didn't work properly with only one argument. In case anyone is interested, here is the corrected version:
/*****************************************************************************
Class CommandLine by Russ Paielli <Russ.Paielli@gmail.com> parses
command-line arguments in a style similar to scala method calls with
named arguments. For example, a program could be invoked with the
command line
myProgram x=123, 22, zz = blah, 43.5, y=t, gg, rr=3.445
The comma-delimited fields can be either assignment-style options (if
"=" is used) or regular arguments. The regular and assignment-style
options can be interwoven arbitrarily. The assignment-style options are
accessed by the name on the left side of the assignment (a String), and
regular arguments are accessed by an integer index (starting with
1). Methods are provided to read arguments of type Int, Double, String,
and Boolean. Booleans can be specified as "t" for "true" or "f" for
"false". The user can specify an optional list of valid options if
desired, in which case an Exception will be thrown if an invalid option
is detected.
Here is an example of its usage (assuming the command line shown above):
def main(args: Array[String]) {
val options = List("x", "y", "zz", "rr", "k", "a") // valid options
val com = new CommandLine(args, options) // "options" is optional!
val x = com.int("x") // read "x" and convert it to an integer
val k = com.int("k", -33) // -33 is the default value if "k" is not found
val rr = com.real("rr") // read "rr" an convert it to a Double
val zz = com.str("zz") // read "zz" as a String
val a2 = com.real(2) // regular argument accessed with Int index
val y = com.bool("y")
val a1 = com.int(1) // regular argument with no default
val a3 = com.int(5, 22) // regular argument with default value 22
}
******************************************************************************/
import scala.collection.mutable.ListBuffer
import scala.collection.mutable.Map
class CommandLine(input: Array[String], val options: List[String]=Nil) {
private val map = Map[String, String]()
private val args = ListBuffer[String]()
if (! input.isEmpty) {
for (field <- input.mkString(" ").trim.split(",")) {
if (field.contains("=")) { // assignment-style argument
val pair = field.split("=")
val key = pair(0).trim
val value = pair(1).trim
checkOption(key)
map(key) = value
}
else args += field.trim // regular (non-assignment) arguments
}
}
private val Nargs = args.length // number of non-assignment arguments
private def checkOption(option: String) {
// check if an option is in the list of valid options (if provided)
if (options.isEmpty) return // empty list of valid options, skip check
if (options.contains(option)) return
val message = "Invalid command-line option: " + option +
"\nvalid options: " + options
throw new RuntimeException(message)
}
private def isSet(option: String): Boolean = { // check if option is set
checkOption(option)
if (map.contains(option)) true else false
}
private def boolx(str: String): String = str match { // shorthand for boolean
case "t" => "true"
case "f" => "false"
case _ => str
}
// read assignment-style options:
def str(option: String, default: String=""): String = // read a String
if (isSet(option)) map(option) else default
def int(option: String, default: Int=0): Int = // read an Int
if (isSet(option)) map(option).toInt else default
def real(option: String, default: Double=0): Double = // read a Double
if (isSet(option)) map(option).toDouble else default
def bool(option: String, default: Boolean=false): Boolean = // read a Boolean
if (isSet(option)) boolx(map(option)).toBoolean else default
// read regular arguments, with default if argument not provided:
def str(i: Int, default: String) =
if (Nargs >= i) args(i-1) else default
def int(i: Int, default: Int) =
if (Nargs >= i) args(i-1).toInt else default
def real(i: Int, default: Double) =
if (Nargs >= i) args(i-1).toDouble else default
def bool(i: Int, default: Boolean) =
if (Nargs >= i) boolx(args(i-1)).toBoolean else default
// read regular arguments, with no default (mandatory arguments):
def str(i: Int) = args(i-1)
def int(i: Int) = args(i-1).toInt
def real(i: Int) = args(i-1).toDouble
def bool(i: Int) = boolx(args(i-1)).toBoolean
}
Ishaaq
[1] https://args4j.dev.java.net/
On 15 March 2010 16:39, Naftoli Gugenheim <naftoligug@gmail.com> wrote: