Hi

I'd like to propose a change to Clojure's current try-catch syntax.

Currently the syntax is (copied from clojure.org)

(try expr* catch-clause* finally-clause?)
catch-clause -> (catch classname name expr*)
finally-clause -> (finally expr*)

I'd like to propose a change to the catch-clause so that it's possible
to specify different classnames one of which will be caught and its
expr evaluated.

It would be something like

(try ...
  (catch SomeException e (println e))
  (catch (SomeOtherException OrAnotherException) e
    (println "xyz" e))
  (finally ...))

In my programming experience I often find that I need to execute the
same code for a few different exceptions but specialized code for some
others and rather than duplicate code (that's why we use lisp right?
no more code duplication!) I thought it would be best that Clojure
support the same.

I saw that it wasn't possible to modify the try syntax from Clojure
itself so I modified the clojure.lang.Compiler file to reflect the
same.

I produced the diff using "svn diff" so patching the same shouldn't be
too hard, I think.

With the new syntax Exceptions can be specified in a List, Vector or a
Set but not a map.  The exceptions must be specified explicitly as
they will not be evaluated.  So

(try
 (foo)
 (catch [InterruptedException MalformedURLException] e (dont (do-what-i-say e)))
 (catch (ArithmeticException NumberFormatException
NullPointerException) e (do-what-i-mean e))
 (catch #{RuntimeException} e)
 (catch Exception e (println e)))

are all legal.  But

(let [excepts [InterruptedException MalformedURLException]]
        (try
         (foo)
         (catch excepts e (println e))))

will throw an IllegalArgumentException.

Java7 will probably have syntax similar to the above
http://tech.puredanger.com/java7#catch

Cheers
Vijay

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Index: src/jvm/clojure/lang/Compiler.java
===================================================================
--- src/jvm/clojure/lang/Compiler.java	(revision 1127)
+++ src/jvm/clojure/lang/Compiler.java	(working copy)
@@ -1800,34 +1800,54 @@
 					{
 					if(Util.equal(op, CATCH))
 						{
-						Class c = HostExpr.maybeClass(RT.second(f), false);
-						if(c == null)
-							throw new IllegalArgumentException("Unable to resolve classname: " + RT.second(f));
-						if(!(RT.third(f) instanceof Symbol))
+                      java.util.Collection exceptions = PersistentVector.EMPTY;
+                      Object second = RT.second(f);
+
+                      if (second instanceof Symbol)
+                          {
+                          exceptions = ((PersistentVector) exceptions).cons(second);
+                          }
+                      else if (second instanceof java.util.Collection)
+                          {
+                          exceptions = (java.util.Collection) second;
+                          }
+                      else
+                          {
+                          throw new IllegalArgumentException(
+                                  "Expected Exception name or sequence of Exception names, got: " + second.getClass());
+                          }
+                      if(!(RT.third(f) instanceof Symbol))
 							throw new IllegalArgumentException(
 									"Bad binding form, expected symbol, got: " + RT.third(f));
-						Symbol sym = (Symbol) RT.third(f);
-						if(sym.getNamespace() != null)
-							throw new Exception("Can't bind qualified name:" + sym);
+                      Symbol sym = (Symbol) RT.third(f);
+                      if(sym.getNamespace() != null)
+                          throw new Exception("Can't bind qualified name:" + sym);
 
-						IPersistentMap dynamicBindings = RT.map(LOCAL_ENV, LOCAL_ENV.get(),
-						                                        NEXT_LOCAL_NUM, NEXT_LOCAL_NUM.get(),
-						                                        IN_CATCH_FINALLY, RT.T);
-						try
-							{
-							Var.pushThreadBindings(dynamicBindings);
-							LocalBinding lb = registerLocal(sym,
-							                                (Symbol) (RT.second(f) instanceof Symbol ? RT.second(f)
-							                                          : null), null);
-							Expr handler = (new BodyExpr.Parser()).parse(context, RT.rest(RT.rest(RT.rest(f))));
-							catches = catches.cons(new CatchClause(c, lb, handler));
-							}
-						finally
-							{
-							Var.popThreadBindings();
-							}
-						caught = true;
-						}
+                      for (Object exception : exceptions)
+                          {
+                          Class c = HostExpr.maybeClass(exception, false);
+                          if(c == null)
+                              throw new IllegalArgumentException("Unable to resolve classname: " + exception);
+
+                          IPersistentMap dynamicBindings = RT.map(LOCAL_ENV, LOCAL_ENV.get(),
+                                  NEXT_LOCAL_NUM, NEXT_LOCAL_NUM.get(),
+                                  IN_CATCH_FINALLY, RT.T);
+                          try
+                              {
+                                  Var.pushThreadBindings(dynamicBindings);
+                                  LocalBinding lb = registerLocal(sym,
+                                          (Symbol) (exception instanceof Symbol ? exception
+                                                  : null), null);
+                                  Expr handler = (new BodyExpr.Parser()).parse(context, RT.rest(RT.rest(RT.rest(f))));
+                                  catches = catches.cons(new CatchClause(c, lb, handler));
+                              }
+                          finally
+                              {
+                                  Var.popThreadBindings();
+                              }
+                          caught = true;
+                          }
+                      }
 					else //finally
 						{
 						if(fs.rest() != null)
@@ -2877,7 +2897,7 @@
 		//fn.thisName = name;
 		String basename = enclosingMethod != null ?
 		                  (enclosingMethod.fn.name + "$")
-		                  : //"clojure.fns." + 
+		                  : //"clojure.fns." +
 		                  (munge(currentNS().name.name) + "$");
 		if(RT.second(form) instanceof Symbol)
 			name = ((Symbol) RT.second(form)).name;
@@ -2997,7 +3017,7 @@
 			{
 		//cv.visitSource(source, null);
 			String smap = "SMAP\n" +
-			              ((source.lastIndexOf('.') > 0) ? 
+			              ((source.lastIndexOf('.') > 0) ?
 			               source.substring(0, source.lastIndexOf('.'))
 			               : simpleName)
 			              + ".java\n" +
@@ -4037,8 +4057,8 @@
 //						Symbol meth = Symbol.intern(sname.substring(idx + 1));
 //						return RT.listStar(DOT, target, meth, form.rest());
 //						}
-					//(StringBuilder. "foo") => (new StringBuilder "foo")	
-					//else 
+					//(StringBuilder. "foo") => (new StringBuilder "foo")
+					//else
 					if(idx == sname.length() - 1)
 						return RT.listStar(NEW, Symbol.intern(sname.substring(0, idx)), form.rest());
 					}
@@ -4473,7 +4493,7 @@
 public static Object compile(Reader rdr, String sourcePath, String sourceName) throws Exception{
 	if(COMPILE_PATH.get() == null)
 		throw new Exception("*compile-path* not set");
-	
+
 	Object EOF = new Object();
 	Object ret = null;
 	LineNumberingPushbackReader pushbackReader =

Reply via email to