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 =