Browse files

Add GetOptException to std.getopt to avoid throwing plain Exception.

  • Loading branch information...
1 parent 786284e commit 4b87dcf39efeb4ddafe8fe99a0ef9a529c0dcaca alexrp committed Feb 18, 2012
Showing with 18 additions and 4 deletions.
  1. +18 −4 std/getopt.d
@@ -79,7 +79,8 @@ void main(string[] args)
to their defaults and then invoke $(D getopt). If a
command-line argument is recognized as an option with a parameter and
the parameter cannot be parsed properly (e.g. a number is expected
- but not present), a $(D ConvException) exception is thrown.
+ but not present), a $(D ConvException) exception is thrown. On all
+ other errors, a $(D GetOptException) exception is thrown.
Depending on the type of the pointer being bound, $(D getopt)
recognizes the following kinds of options:
@@ -346,6 +347,18 @@ void getopt(T...)(ref string[] args, T opts) {
+ * Thrown if an error occurs while parsing the command line.
+ */
+class GetOptException : Exception
+ this(string s, string fn = __FILE__, size_t ln = __LINE__)
+ {
+ super(s, fn, ln);
+ }
* Configuration options for $(D getopt). You can pass them to $(D
* getopt) in any position, except in between an option string and its
* bound pointer.
@@ -408,7 +421,7 @@ private void getoptImpl(T...)(ref string[] args,
if (endOfOptions.length && a == endOfOptions) break;
if (!cfg.passThrough)
- throw new Exception("Unrecognized option "~a);
+ throw new GetOptException("Unrecognized option " ~ a ~ ".");
@@ -464,8 +477,9 @@ void handleOption(R)(string option, R receiver, ref string[] args,
if (!isDelegateWithLessThanTwoParameters && !(val.length) && !incremental) {
// Eat the next argument too. Check to make sure there's one
// to be eaten first, though.
- enforce(i < args.length,
- "Missing value for argument " ~ a ~ ".");
+ if (i >= args.length)
+ throw new GetOptException("Missing value for argument " ~ a ~ ".");
val = args[i];
args = args[0 .. i] ~ args[i + 1 .. $];

5 comments on commit 4b87dcf


I'll prefer to hold off on this. I generally disagree with the notion there should be many exception types (and consequently one per module). A better solution is to include the module name in the exception fields. Anyhow, we must carefully review our general doctrine on exceptions.

alexrp commented on 4b87dcf Feb 18, 2012

The entire point of specific exception types is to not erroneously catch exceptions you did not intend to catch. It's not about per-module exceptions, it's simply about correctness of catch blocks. Throwing plain Exception encourages swallowing errors you did not intend to.

Encoding the module name in the exception is not sufficient. That forces me to check some field of the caught exception rather than just catching a specific type of exception. This approach would also mean that I have to rethrow the exception if I do not wish to handle it. That's just annoying... and also resets the stack trace, making debugging a nightmare.


The converse point is that the whole purpose of exceptions is to enable centralized error handling, and distinguishing them by type encourages the exact opposite.

More to the point, in most C++ applications I worked with, there was no meaningful use of distinct exception types.


Let's take this to the newsgroup and start a flame war. I'm sure something good will come out of it. For my money, I don't know what the right way is, but I feel yours isn't.

alexrp commented on 4b87dcf Feb 18, 2012

Yes, I did notice this trend back when I worked with C++.

However, if you look at most C# or Java applications, it's the complete opposite: People try to catch specific exceptions such that exceptions that indicate underlying problems can surface and be noticed, rather than silenced and potentially ignored. Catching everything is good in some applications, because reliability (i.e. don't crash on an unhandled exception) is very important. In others, correctness is MUCH more important (compilers, virtual machines, that sort of thing). In those cases, you want to know as soon as possible when something is wrong so you can fix it.

Now, that argument doesn't really hold water in the case of std.getopt of all things, but I do think that we need a consistent design across all of Phobos.

Please sign in to comment.