From: Peter G. <pe...@ar...> - 2005-10-25 19:10:26
|
Hi Andras, What is the status of REGISTER-JAVA-EXCEPTION? I can't find any calls to it in src/org/armedbear/lisp/*.lisp. The idea seems reasonable, but the implementation doesn't seem very robust (for example, there's no code to ensure that the symbol argument actually names a condition), so it looks a bit experimental. The larger problem is that global mappings don't give you granularity, so you can't map a particular exception class to condition A for call A and to condition B for call B, for example. We probably do need to report exceptions thrown by Java code invoked by JCALL and friends, but I think it might make more sense to define some sort of JAVA-CONDITION that would just encapsulate the thrown Java exception. Then user code could simply HANDLER-BIND or HANDLER-CASE JAVA-CONDITION and dispatch on the encapsulated exception. What do you think? -Peter |
From: Andras S. <as...@ma...> - 2005-10-25 22:11:29
|
On Tue, 25 Oct 2005, Peter Graves wrote: > Hi Andras, > > What is the status of REGISTER-JAVA-EXCEPTION? The short answer is that it's a reminder that something like it would be nice... The longer is buried in these messages: http://sourceforge.net/mailarchive/message.php?msg_id=10626371 http://sourceforge.net/mailarchive/message.php?msg_id=10626999 http://sourceforge.net/mailarchive/message.php?msg_id=10628238 I can't recall what problems I ran into later. They may have had something to do with PRINT-OBJECT not doing what it was meant to, and this causing problems with popping up restarts in the slime debugger. > > I can't find any calls to it in src/org/armedbear/lisp/*.lisp. That in itself wouldn't necessarily be a problem. The only place in ABCL's sources where this could be useful is probably java.lisp. > > The idea seems reasonable, but the implementation doesn't seem very > robust (for example, there's no code to ensure that the symbol argument > actually names a condition), so it looks a bit experimental. It certainly is. > > The larger problem is that global mappings don't give you granularity, > so you can't map a particular exception class to condition A for call A > and to condition B for call B, for example. That's true, but isn't it the _handling_ of the condition that should vary from call to call? My - perhaps too simplistic - idea was that there would be a DEF-JAVA-EXCEPTION macro analogous to (an imaginary, or jfli's) DEF-JAVA-CLASS, so one can more less automatically work with conditions instead of having to deal with Java exceptions. > > We probably do need to report exceptions thrown by Java code invoked by > JCALL and friends, but I think it might make more sense to define some > sort of JAVA-CONDITION that would just encapsulate the thrown Java > exception. Then user code could simply HANDLER-BIND or HANDLER-CASE > JAVA-CONDITION and dispatch on the encapsulated exception. It's not clear to me how one could dispatch on the Java exception. And isn't the whole point of all this is to not to have to worry about exceptions, but only conditions? But I may very well be missing something! Andras |
From: Peter G. <pe...@ar...> - 2005-10-26 14:40:33
|
On Wed, 26 Oct 2005 at 00:11:18 +0200, Andras Simon wrote: > > The larger problem is that global mappings don't give you granularity, > > so you can't map a particular exception class to condition A for call A > > and to condition B for call B, for example. > > That's true, but isn't it the _handling_ of the condition that should > vary from call to call? My - perhaps too simplistic - idea was that > there would be a DEF-JAVA-EXCEPTION macro analogous to (an imaginary, > or jfli's) DEF-JAVA-CLASS, so one can more less automatically work > with conditions instead of having to deal with Java exceptions. I misunderstood what was going on. In the first of the three messages you referenced (a conversation I had totally forgotten until you reminded me) you gave a nice example of how this mechanism is supposed to work: (define-condition illegal-argument (error) ()) (register-java-exception "java.lang.IllegalArgumentException" 'illegal-argument) (jstatic (jmethod "java.lang.String" "valueOf" "int") "java.lang.String" 23.1) Debugger invoked on condition of type ILLEGAL-ARGUMENT: # Restarts: 0: ABORT Abort handling SLIME request. So far so good. I think the idea of a DEF-JAVA-EXCEPTION macro is a good one, too. So instead of: (define-condition illegal-argument (error) ()) (register-java-exception "java.lang.IllegalArgumentException" 'illegal-argument) you could just do: (def-java-exception illegal-argument "java.lang.IllegalArgumentException") Or maybe even just (def-java-exception "java.lang.IllegalArgumentException") and some sort of magic would happen that would define a condition called java.lang.illegal-argument-exception. OK. In the last of the three referenced messages, you suggested: And now I think that adding a few slots to conditions that are signaled when Java exceptions are raised would be a good thing. To keep entropy at bay, a condition JAVA-EXCEPTION could be defined with just two slots: MESSAGE and STACK-TRACE. It would report the MESSAGE only. Users could subclass this condition, and expect the two slots to be filled in when it is signaled. So DEF-JAVA-EXCEPTION would define a condition that would be a subclass of JAVA-EXCEPTION (rather than ERROR, as in the examble above). OK. (But I think we might only need one slot, which would be filled in with a JAVA-OBJECT that wrapped the original Java Throwable object. That way we'd never lose any of the information from the original Throwable, if by some chance it contained more than MESSAGE and STACK-TRACE.) > > We probably do need to report exceptions thrown by Java code invoked by > > JCALL and friends, but I think it might make more sense to define some > > sort of JAVA-CONDITION that would just encapsulate the thrown Java > > exception. Then user code could simply HANDLER-BIND or HANDLER-CASE > > JAVA-CONDITION and dispatch on the encapsulated exception. > > It's not clear to me how one could dispatch on the Java exception. I was thinking of JAVA-CONDITION as being roughly equivalent to your JAVA-EXCEPTION, except with just one slot for the original Java Throwable. Then the user could dispatch on the contents of that slot by hand in the HANDLER-CASE clause: (handler-case (jcall x y) (java-exception (c) (let* ((throwable (java-exception-throwable c)) (class-name (jclass-of throwable))) (cond ((equal class-name "java.lang.ClassCastException") (do-something)) ((equal class-name "java.lang.NullPointerException") (do-something-else)))))) Which, admittedly, is pretty awkward compared to: (handler-case (jcall x y) (java.lang.class-cast-exception (c) (do-something)) (java.lang.null-pointer-exception (c) (do-something-else)) > And isn't the whole point of all this is to not to have to worry about > exceptions, but only conditions? But I may very well be missing > something! No, I think you're absolutely right. But I still have a question (maybe more than one, but one for now). Consider an application that uses multiple third-party library modules. One module might do (define-condition null-pointer-error (java-exception) ()) (register-java-exception "java.lang.IllegalArgumentException" 'null-pointer-error) and another module might do (define-condition null-pointer-exception (java-exception) ()) (register-java-exception "java.lang.IllegalArgumentException" 'null-pointer-exception) It seems like whichever of these modules is loaded last will get its way with the handling of NullPointerExceptions, and the other one won't see them at all. This is what I was getting at when I complained that global mappings don't give you granularity. What should we do about this? -Peter |
From: Peter G. <pe...@ar...> - 2005-10-26 14:57:04
|
On Wed, 26 Oct 2005 at 07:40:15 -0700, Peter Graves wrote: > One module might do > > (define-condition null-pointer-error (java-exception) ()) > (register-java-exception "java.lang.IllegalArgumentException" > 'null-pointer-error) > > and another module might do > > (define-condition null-pointer-exception (java-exception) ()) > (register-java-exception "java.lang.IllegalArgumentException" > 'null-pointer-exception) > > It seems like whichever of these modules is loaded last will get its > way with the handling of NullPointerExceptions, and the other one won't > see them at all. This is what I was getting at when I complained that > global mappings don't give you granularity. > > What should we do about this? My example contains a cut-and-paste error that muddies the waters. It should have been: One module might do (define-condition null-pointer-error (java-exception) ()) (register-java-exception "java.lang.NullPointerException" ^^^^^^^^^^^^^^^^^^^^ 'null-pointer-error) and another module might do (define-condition null-pointer-exception (java-exception) ()) (register-java-exception "java.lang.NullPointerException" ^^^^^^^^^^^^^^^^^^^^ 'null-pointer-exception) -Peter |
From: Andras S. <as...@ma...> - 2005-10-26 16:48:00
|
On Wed, 26 Oct 2005, Peter Graves wrote: > On Wed, 26 Oct 2005 at 00:11:18 +0200, Andras Simon wrote: >>> The larger problem is that global mappings don't give you granularity, >>> so you can't map a particular exception class to condition A for call A >>> and to condition B for call B, for example. >> >> That's true, but isn't it the _handling_ of the condition that should >> vary from call to call? My - perhaps too simplistic - idea was that >> there would be a DEF-JAVA-EXCEPTION macro analogous to (an imaginary, >> or jfli's) DEF-JAVA-CLASS, so one can more less automatically work >> with conditions instead of having to deal with Java exceptions. > > I misunderstood what was going on. > > In the first of the three messages you referenced (a conversation I had > totally forgotten until you reminded me) you gave a nice example of how > this mechanism is supposed to work: > > (define-condition illegal-argument (error) ()) > > (register-java-exception "java.lang.IllegalArgumentException" 'illegal-argument) > > (jstatic (jmethod "java.lang.String" "valueOf" "int") "java.lang.String" 23.1) > Debugger invoked on condition of type ILLEGAL-ARGUMENT: > # > Restarts: > 0: ABORT Abort handling SLIME request. > Somewhat surprisingly (since this part of ABCL hasn't been touched for a long time, and probably noone's using it), it's not only how it's supposed to work, it's how it actually works! > So far so good. > > I think the idea of a DEF-JAVA-EXCEPTION macro is a good one, too. So > instead of: > > (define-condition illegal-argument (error) ()) > (register-java-exception "java.lang.IllegalArgumentException" 'illegal-argument) > > you could just do: > > (def-java-exception illegal-argument "java.lang.IllegalArgumentException") > > Or maybe even just > > (def-java-exception "java.lang.IllegalArgumentException") > > and some sort of magic would happen that would define a condition > called java.lang.illegal-argument-exception. > > OK. Yes, register-java-exception was meant to be the low-level mechanism on top of which a fancy def-java-exception macro could be built eventually. Just as jcall and friends are the foundation for jfli. > > In the last of the three referenced messages, you suggested: > > And now I think that adding a few slots to conditions that are > signaled when Java exceptions are raised would be a good thing. To > keep entropy at bay, a condition JAVA-EXCEPTION could be defined > with just two slots: MESSAGE and STACK-TRACE. It would report the > MESSAGE only. Users could subclass this condition, and expect the > two slots to be filled in when it is signaled. > > So DEF-JAVA-EXCEPTION would define a condition that would be a subclass > of JAVA-EXCEPTION (rather than ERROR, as in the examble above). I even have a JavaException (a subclass of LispError) lying around; but I can't recall what its purpose in life was, or why I abandoned it. I must've run into something because it looks very, hmmm, sparse. > > OK. > > (But I think we might only need one slot, which would be filled in with > a JAVA-OBJECT that wrapped the original Java Throwable object. That way > we'd never lose any of the information from the original Throwable, if > by some chance it contained more than MESSAGE and STACK-TRACE.) I originally wanted to have slots in the condition corresponding to all (or at least a big subset of) the methods of the Java exception, that would be filled in by invoking those methods. But then I thought (or you suggested) that that was an overkill (and would probably be too slow anyway). So, as a compromise, I opted for just two slots: the message and the stack trace. (That's where the allusion to entropy comes from.) But message + the throwable itself is probably a better compromise. > >>> We probably do need to report exceptions thrown by Java code invoked by >>> JCALL and friends, but I think it might make more sense to define some >>> sort of JAVA-CONDITION that would just encapsulate the thrown Java >>> exception. Then user code could simply HANDLER-BIND or HANDLER-CASE >>> JAVA-CONDITION and dispatch on the encapsulated exception. >> >> It's not clear to me how one could dispatch on the Java exception. > > I was thinking of JAVA-CONDITION as being roughly equivalent to your > JAVA-EXCEPTION, except with just one slot for the original Java > Throwable. > > Then the user could dispatch on the contents of that slot by hand in > the HANDLER-CASE clause: > > (handler-case > (jcall x y) > (java-exception (c) > (let* ((throwable (java-exception-throwable c)) > (class-name (jclass-of throwable))) > (cond ((equal class-name "java.lang.ClassCastException") > (do-something)) > ((equal class-name "java.lang.NullPointerException") > (do-something-else)))))) > > Which, admittedly, is pretty awkward compared to: Not only that, but it's also very much against the spirit of the CL condition system. (Or that is how it looks to me; I'm no condition system guru: far from it!) > > (handler-case > (jcall x y) > (java.lang.class-cast-exception (c) (do-something)) > (java.lang.null-pointer-exception (c) (do-something-else)) I think that this is the good direction. > >> And isn't the whole point of all this is to not to have to worry about >> exceptions, but only conditions? But I may very well be missing >> something! > > No, I think you're absolutely right. > > But I still have a question (maybe more than one, but one for now). > > Consider an application that uses multiple third-party library modules. > One module might do > > (define-condition null-pointer-error (java-exception) ()) > (register-java-exception "java.lang.IllegalArgumentException" > 'null-pointer-error) > > and another module might do > > (define-condition null-pointer-exception (java-exception) ()) > (register-java-exception "java.lang.IllegalArgumentException" > 'null-pointer-exception) > > It seems like whichever of these modules is loaded last will get its > way with the handling of NullPointerExceptions, and the other one won't > see them at all. This is what I was getting at when I complained that > global mappings don't give you granularity. > > What should we do about this? Perhaps we could avoid it by having (def-java-exception "java.lang.IllegalArgumentException") as opposed to (def-java-exception illegal-argument "java.lang.IllegalArgumentException") i.e. by not letting the user mess with exceptions too much. This seems like a relatively clean if not very flexible approach. Or we could signal a continuable error in case of a redefinition (or should I say re-registration?) attempt. (I like this the best.) There could also be a rebinding mechanism (as with dynamic variables) but that somehow feels wrong (and an overkill) to me. Not that I see clearly what this would involve. The longer I look at it, the more I like the second option. Especially, for a 0.1 release. We just don't have enough experience to know if it'll hurt anyone, so why draw up elaborate plans to avoid the pain that may never come. And option no. 2 also leaves room for some experimentation. Motto: People should be creative in how they deal with errors, not how they name it. What do you think? Andras |
From: Peter G. <pe...@ar...> - 2005-10-27 12:27:59
|
On Wed, 26 Oct 2005 at 18:47:48 +0200, Andras Simon wrote: > On Wed, 26 Oct 2005, Peter Graves wrote: > > > > Consider an application that uses multiple third-party library modules. > > One module might do > > > > (define-condition null-pointer-error (java-exception) ()) > > (register-java-exception "java.lang.IllegalArgumentException" > > 'null-pointer-error) > > > > and another module might do > > > > (define-condition null-pointer-exception (java-exception) ()) > > (register-java-exception "java.lang.IllegalArgumentException" > > 'null-pointer-exception) > > > > It seems like whichever of these modules is loaded last will get its > > way with the handling of NullPointerExceptions, and the other one won't > > see them at all. This is what I was getting at when I complained that > > global mappings don't give you granularity. > > > > What should we do about this? > > Perhaps we could avoid it by having > > (def-java-exception "java.lang.IllegalArgumentException") > > as opposed to > > (def-java-exception illegal-argument "java.lang.IllegalArgumentException") > > i.e. by not letting the user mess with exceptions too much. This seems > like a relatively clean if not very flexible approach. Yeah, this is essentially the jFli approach, applied to the subject of exceptions. I think this approach is fine, but it's a higher level approach, and should be part of the higher level API, which is not really what we're talking about here. > Or we could signal a continuable error in case of a redefinition (or > should I say re-registration?) attempt. (I like this the best.) OK. > There could also be a rebinding mechanism (as with dynamic variables) > but that somehow feels wrong (and an overkill) to me. Not that I see > clearly what this would involve. I don't really see what this would involve either, and it does seem like overkill, so let's not go down that road. > The longer I look at it, the more I like the second option. I think that's a fine plan (the second option being a continuable error in case of a re-registration attempt, just to be perfectly clear). > Especially, for a 0.1 release. We just don't have enough experience to > know if it'll hurt anyone, so why draw up elaborate plans to avoid the > pain that may never come. And option no. 2 also leaves room for some > experimentation. > > Motto: People should be creative in how they deal with errors, not how > they name it. > > What do you think? I think there's at least one further issue. Suppose (for the sake of argument) you do: (define-condition throwable (java-exception) ()) (register-java-exception "java.lang.Throwable" 'throwable) And then some call to Java throws a NullPointerException (for example). Now, you haven't registered "java.lang.NullPointerException". But from Java's point of view, a NullPointerException _is_ a Throwable, so the condition registered for "java.lang.Throwable" should arguably be signalled. You can't accomplish this with a simple hashtable lookup of "java.lang.NullPointerException". You'd have to walk the list of registered exceptions and check to see if the class of the exception at hand is either identical to, or a subclass of, one of the registered exception classes. And the order in which you walked the list would matter, in exactly the same way the order of catch clauses matters after a try block in Java code. Having mentioned this issue, I don't plan to do anything about it right now. For the moment, I think I'm going to leave the registration mechanism as it is, except that I do plan to introduce a JavaException class, more or less as we've discussed it, and make sure that when no exceptions are registered, Java exceptions are caught and a well-formed JavaException (or JAVA-EXCEPTION) is signalled on the Lisp side, with a plausible error message. This should be reasonably safe, while leaving plenty of room for experimentation while we acquire the experience that will enable us to do a better job somewhere down the road, when we have real users complaining about real problems. Thanks for your help with this! -Peter |
From: Peter G. <pe...@ar...> - 2005-10-28 17:26:37
|
On Thu, 27 Oct 2005 at 05:27:45 -0700, Peter Graves wrote: > For the moment, I think I'm going to leave the registration mechanism > as it is, except that I do plan to introduce a JavaException class, > more or less as we've discussed it, and make sure that when no > exceptions are registered, Java exceptions are caught and a well-formed > JavaException (or JAVA-EXCEPTION) is signalled on the Lisp side, with a > plausible error message. Done. For example: CL-USER(1): (jnew (jconstructor "java.lang.String" "java.lang.String") (make-immediate-object nil :ref)) Debugger invoked on condition of type JAVA-EXCEPTION: java.lang.reflect.InvocationTargetException at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:274) at org.armedbear.lisp.Java$9.execute(Java.java:376) at org.armedbear.lisp.Primitive.execute(Primitive.java:102) at org.armedbear.lisp.LispThread.execute(LispThread.java:621) at org.armedbear.lisp.Lisp.evalCall(Lisp.java:424) at org.armedbear.lisp.Lisp.eval(Lisp.java:391) at org.armedbear.lisp.Primitives$16.execute(Primitives.java:268) at org.armedbear.lisp.LispThread.execute(LispThread.java:603) at org.armedbear.lisp.Lisp.evalCall(Lisp.java:418) at org.armedbear.lisp.Lisp.eval(Lisp.java:391) at org.armedbear.lisp.Primitives$136.execute(Primitives.java:3378) at org.armedbear.lisp.Lisp.eval(Lisp.java:380) at org.armedbear.lisp.Closure.execute(Closure.java:388) at org.armedbear.lisp.LispThread.execute(LispThread.java:603) at org.armedbear.lisp.Lisp$1.execute(Lisp.java:250) at org.armedbear.lisp.Symbol.execute(Symbol.java:666) at org.armedbear.lisp.LispThread.execute(LispThread.java:603) at org.armedbear.lisp.top_level_44.execute(top-level.lisp:390) at org.armedbear.lisp.CompiledFunction.execute(CompiledFunction.java:51) at org.armedbear.lisp.Symbol.execute(Symbol.java:656) at org.armedbear.lisp.LispThread.execute(LispThread.java:586) at org.armedbear.lisp.top_level_45.execute(top-level.lisp:399) at org.armedbear.lisp.LispThread.execute(LispThread.java:586) at org.armedbear.lisp.Interpreter.run(Interpreter.java:361) at org.armedbear.lisp.Main.main(Main.java:32) Caused by: java.lang.NullPointerException at java.lang.String.<init>(String.java:141) ... 28 more Restarts: 0: TOP-LEVEL Return to top level. [1] CL-USER(2): (describe *debug-condition*) #<JAVA-EXCEPTION {E38FAE}> is an object of type JAVA-EXCEPTION. [1] CL-USER(3): (inspect *debug-condition*) 0 LAYOUT -----------> #<SYSTEM:LAYOUT {1EDC290}> 1 FORMAT-CONTROL ---> NIL 2 FORMAT-ARGUMENTS -> NIL 3 CAUSE ------------> #<JAVA-OBJECT java.lang.reflect.InvocationTargetException {80B973}> [2i] CL-USER(4): :reset CL-USER(5): Thanks for your support. -Peter |
From: Andras S. <as...@ma...> - 2005-10-29 10:24:36
|
On Fri, 28 Oct 2005, Peter Graves wrote: > On Thu, 27 Oct 2005 at 05:27:45 -0700, Peter Graves wrote: >> For the moment, I think I'm going to leave the registration mechanism >> as it is, except that I do plan to introduce a JavaException class, >> more or less as we've discussed it, and make sure that when no >> exceptions are registered, Java exceptions are caught and a well-formed >> JavaException (or JAVA-EXCEPTION) is signalled on the Lisp side, with a >> plausible error message. > > Done. > > For example: > > CL-USER(1): (jnew (jconstructor "java.lang.String" "java.lang.String") > (make-immediate-object nil :ref)) > Debugger invoked on condition of type JAVA-EXCEPTION: > java.lang.reflect.InvocationTargetException Since this exception is an artifact of our using reflection behind the scenes, I think it would make sense to get the real cause (by getCause()) and present that to the user (and also to check that on the registered exceptions list). Then we'd have CL-USER(5): (jnew (jconstructor "java.lang.String" "java.lang.String") (make-immediate-object nil :ref)) Debugger invoked on condition of type JAVA-EXCEPTION: java.lang.NullPointerException at java.lang.String.<init>(String.java:144) ... [1] CL-USER(7): (inspect *debug-condition*) 0 LAYOUT -----------> #<SYSTEM:LAYOUT {176ED77}> 1 FORMAT-CONTROL ---> NIL 2 FORMAT-ARGUMENTS -> NIL 3 CAUSE ------------> #<JAVA-OBJECT java.lang.NullPointerException {E02FC4}> and CL-USER(9): (jnew (jconstructor "java.lang.String" "java.lang.String") 23) Debugger invoked on condition of type JAVA-EXCEPTION: java.lang.IllegalArgumentException: argument type mismatch [1] CL-USER(10): (inspect *debug-condition*) 0 LAYOUT -----------> #<SYSTEM:LAYOUT {176ED77}> 1 FORMAT-CONTROL ---> NIL 2 FORMAT-ARGUMENTS -> NIL 3 CAUSE ------------> #<JAVA-OBJECT java.lang.IllegalArgumentException {600A08}> Perhaps a good rule of thumb is that exceptions that are in the java.lang.reflect package should be replaced with their causes, and all other exceptions should be left alone. One possible problem with this is if the user is doing her own reflection. Andras |
From: Andras S. <as...@ma...> - 2005-10-30 12:40:18
|
On Fri, 28 Oct 2005, Peter Graves wrote: > On Thu, 27 Oct 2005 at 05:27:45 -0700, Peter Graves wrote: >> For the moment, I think I'm going to leave the registration mechanism >> as it is, except that I do plan to introduce a JavaException class, >> more or less as we've discussed it, and make sure that when no >> exceptions are registered, Java exceptions are caught and a well-formed >> JavaException (or JAVA-EXCEPTION) is signalled on the Lisp side, with a >> plausible error message. > > Done. > > For example: > > CL-USER(1): (jnew (jconstructor "java.lang.String" "java.lang.String") > (make-immediate-object nil :ref)) > Debugger invoked on condition of type JAVA-EXCEPTION: > java.lang.reflect.InvocationTargetException > at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) > at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) > at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) > at java.lang.reflect.Constructor.newInstance(Constructor.java:274) > at org.armedbear.lisp.Java$9.execute(Java.java:376) > at org.armedbear.lisp.Primitive.execute(Primitive.java:102) > at org.armedbear.lisp.LispThread.execute(LispThread.java:621) > at org.armedbear.lisp.Lisp.evalCall(Lisp.java:424) > at org.armedbear.lisp.Lisp.eval(Lisp.java:391) > at org.armedbear.lisp.Primitives$16.execute(Primitives.java:268) > at org.armedbear.lisp.LispThread.execute(LispThread.java:603) > at org.armedbear.lisp.Lisp.evalCall(Lisp.java:418) > at org.armedbear.lisp.Lisp.eval(Lisp.java:391) > at org.armedbear.lisp.Primitives$136.execute(Primitives.java:3378) > at org.armedbear.lisp.Lisp.eval(Lisp.java:380) > at org.armedbear.lisp.Closure.execute(Closure.java:388) > at org.armedbear.lisp.LispThread.execute(LispThread.java:603) > at org.armedbear.lisp.Lisp$1.execute(Lisp.java:250) > at org.armedbear.lisp.Symbol.execute(Symbol.java:666) > at org.armedbear.lisp.LispThread.execute(LispThread.java:603) > at org.armedbear.lisp.top_level_44.execute(top-level.lisp:390) > at org.armedbear.lisp.CompiledFunction.execute(CompiledFunction.java:51) > at org.armedbear.lisp.Symbol.execute(Symbol.java:656) > at org.armedbear.lisp.LispThread.execute(LispThread.java:586) > at org.armedbear.lisp.top_level_45.execute(top-level.lisp:399) > at org.armedbear.lisp.LispThread.execute(LispThread.java:586) > at org.armedbear.lisp.Interpreter.run(Interpreter.java:361) > at org.armedbear.lisp.Main.main(Main.java:32) > Caused by: java.lang.NullPointerException > at java.lang.String.<init>(String.java:141) > ... 28 more > Restarts: > 0: TOP-LEVEL Return to top level. > [1] CL-USER(2): (describe *debug-condition*) > #<JAVA-EXCEPTION {E38FAE}> is an object of type JAVA-EXCEPTION. > [1] CL-USER(3): (inspect *debug-condition*) > 0 LAYOUT -----------> #<SYSTEM:LAYOUT {1EDC290}> > 1 FORMAT-CONTROL ---> NIL > 2 FORMAT-ARGUMENTS -> NIL > 3 CAUSE ------------> #<JAVA-OBJECT java.lang.reflect.InvocationTargetException {80B973}> > [2i] CL-USER(4): :reset > CL-USER(5): There are a few things that I don't understand about this. Why don't conditions that are subclasses of JAVA-EXCEPTION inherit the cause slot? And where does the message disappear? It is passed to signal, as in signal(condition, new SimpleString(getMessage(t))) Is any of this related to my messing with exceptions? Ideally, what I think should happen is that any condition that is a subtype of JAVA-EXCEPTION has a CAUSE and a MESSAGE slot (with readers and all), and they get filled in when the condition is signaled. How could I arrange this? Andras |
From: Peter G. <pe...@ar...> - 2005-10-30 13:31:52
|
On Sun, 30 Oct 2005 at 13:40:05 +0100, Andras Simon wrote: > There are a few things that I don't understand about this. Why don't > conditions that are subclasses of JAVA-EXCEPTION inherit the cause > slot? They do: CL-USER(1): (define-condition throwable (java-exception) ()) THROWABLE CL-USER(2): (signal 'throwable) Debugger invoked on condition of type THROWABLE: #<THROWABLE {374956}> Restarts: 0: TOP-LEVEL Return to top level. [1] CL-USER(3): (inspect *debug-condition*) 0 LAYOUT -----------> #<SYSTEM:LAYOUT {1FC1B56}> 1 CAUSE ------------> #<UNBOUND> 2 FORMAT-CONTROL ---> #<UNBOUND> 3 FORMAT-ARGUMENTS -> #<UNBOUND> [2i] CL-USER(4): > And where does the message disappear? It is passed to signal, as > in > > signal(condition, new SimpleString(getMessage(t))) Yes, but that just passes the message to the real SIGNAL, defined in signal.lisp: public static final LispObject signal(LispObject condition, LispObject message) throws ConditionThrowable { return Symbol.SIGNAL.execute(condition, Keyword.MESSAGE, message); } I don't think the :message keyword is used anywhere else, so this doesn't make much sense, and that signal() function should go away. The underlying problem is that conditions don't have a MESSAGE slot. The Java class Condition has a message field: protected String message = null; But that's very old, and dates back to a time when ABCL's conditions weren't CLOS objects. That field should probably go away too, but there are vestiges of it in a number of places. The right way to do things nowadays is to use the FORMAT-CONTROL slot (via the :format-control initarg), which all instances of subclasses of CONDITION have. That said, there's clearly a bug in this area: CL-USER(21): (define-condition test-error (program-error) ()) TEST-ERROR CL-USER(23): (error 'test-error :format-control "this is a test") Debugger invoked on condition of type TEST-ERROR: Debugger invoked on condition of type TYPE-ERROR: The value #<UNBOUND> is not of type LIST. Restarts: 0: TOP-LEVEL Return to top level. I'll try to fix that later today. > Is any of this related to my messing with exceptions? I don't think so, since the problem occurs with conditions derived from PROGRAM-ERROR too. > Ideally, what I think should happen is that any condition that is a > subtype of JAVA-EXCEPTION has a CAUSE and a MESSAGE slot (with readers > and all), and they get filled in when the condition is signaled. The CAUSE slot should be there, and JAVA:JAVA-EXCEPTION-CAUSE is the reader for it. As mentioned, there is no MESSAGE slot. > How could I arrange this? I'll let you know after I figure out what the bug is. Stay tuned... :) -Peter |
From: Peter G. <pe...@ar...> - 2005-10-31 13:13:22
|
On Sun, 30 Oct 2005 at 05:31:38 -0800, Peter Graves wrote: > That said, there's clearly a bug in this area: > > CL-USER(21): (define-condition test-error (program-error) ()) > TEST-ERROR > CL-USER(23): (error 'test-error :format-control "this is a test") > Debugger invoked on condition of type TEST-ERROR: > > Debugger invoked on condition of type TYPE-ERROR: > The value #<UNBOUND> is not of type LIST. > Restarts: > 0: TOP-LEVEL Return to top level. > > I'll try to fix that later today. It turned out not to be so easy. There are some serious inconsistencies in the condition system, and I'd like to fix them properly. I expect this will take a few days, at a minimum. -Peter |
From: Peter G. <pe...@ar...> - 2005-11-04 20:18:46
|
On Mon, 31 Oct 2005 at 05:12:56 -0800, Peter Graves wrote: > On Sun, 30 Oct 2005 at 05:31:38 -0800, Peter Graves wrote: > > That said, there's clearly a bug in this area: > > > > CL-USER(21): (define-condition test-error (program-error) ()) > > TEST-ERROR > > CL-USER(23): (error 'test-error :format-control "this is a test") > > Debugger invoked on condition of type TEST-ERROR: > > > > Debugger invoked on condition of type TYPE-ERROR: > > The value #<UNBOUND> is not of type LIST. > > Restarts: > > 0: TOP-LEVEL Return to top level. > > > > I'll try to fix that later today. > > It turned out not to be so easy. > > There are some serious inconsistencies in the condition system, and I'd > like to fix them properly. > > I expect this will take a few days, at a minimum. This is now fixed in CVS: CL-USER(1): (define-condition test-error (program-error) ()) TEST-ERROR CL-USER(2): (error 'test-error :format-control "this is a test") Debugger invoked on condition of type TEST-ERROR: this is a test Restarts: 0: TOP-LEVEL Return to top level. [1] CL-USER(3): With the latest changes, the condition system is in considerably better shape overall, but there's still a bit of cleanup to be done. Thanks for your patience. -Peter |
From: Andras S. <as...@ma...> - 2005-11-04 20:30:51
|
On Fri, 4 Nov 2005, Peter Graves wrote: > On Mon, 31 Oct 2005 at 05:12:56 -0800, Peter Graves wrote: >> On Sun, 30 Oct 2005 at 05:31:38 -0800, Peter Graves wrote: >>> That said, there's clearly a bug in this area: >>> >>> CL-USER(21): (define-condition test-error (program-error) ()) >>> TEST-ERROR >>> CL-USER(23): (error 'test-error :format-control "this is a test") >>> Debugger invoked on condition of type TEST-ERROR: >>> >>> Debugger invoked on condition of type TYPE-ERROR: >>> The value #<UNBOUND> is not of type LIST. >>> Restarts: >>> 0: TOP-LEVEL Return to top level. >>> >>> I'll try to fix that later today. >> >> It turned out not to be so easy. >> >> There are some serious inconsistencies in the condition system, and I'd >> like to fix them properly. >> >> I expect this will take a few days, at a minimum. > > This is now fixed in CVS: > > CL-USER(1): (define-condition test-error (program-error) ()) > TEST-ERROR > CL-USER(2): (error 'test-error :format-control "this is a test") > Debugger invoked on condition of type TEST-ERROR: > this is a test > Restarts: > 0: TOP-LEVEL Return to top level. > [1] CL-USER(3): > > With the latest changes, the condition system is in considerably better > shape overall, but there's still a bit of cleanup to be done. This is great news! But I get this while doing a full compile: Primitives.java:3913: cannot find symbol symbol : constructor TypeError(org.armedbear.lisp.LispObject,java.lang.String) location: class org.armedbear.lisp.TypeError return signal(new TypeError(arg, "output stream")); ^ Closure.java:1166: cannot find symbol symbol : constructor TypeError(org.armedbear.lisp.LispObject,java.lang.String) location: class org.armedbear.lisp.TypeError return signal(new TypeError(arg, "closure")); ^ Note: Some input files use unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. 2 errors Build failed. Andras |
From: Peter G. <pe...@ar...> - 2005-11-04 20:47:44
|
On Sun, 30 Oct 2005 at 13:40:05 +0100, Andras Simon wrote: > There are a few things that I don't understand about this. Why don't > conditions that are subclasses of JAVA-EXCEPTION inherit the cause > slot? And where does the message disappear? It is passed to signal, as > in > > signal(condition, new SimpleString(getMessage(t))) I've fixed signal() at Lisp.java:303 to use the :FORMAT-CONTROL initarg, which ABCL (like Allegro) supports for CONDITIONs as well as SIMPLE-CONDITIONs: public static final LispObject signal(LispObject condition, LispObject message) throws ConditionThrowable { return Symbol.SIGNAL.execute(condition, Keyword.FORMAT_CONTROL, message); } where the first argument is normally a symbol designating a subtype of CONDITION. This is what you'd do in Java to get the equivalent of: (signal 'some-condition :format-control "some message") The calls to signal() in Java.java now work more or less as intended. > Ideally, what I think should happen is that any condition that is a > subtype of JAVA-EXCEPTION has a CAUSE and a MESSAGE slot (with readers > and all), and they get filled in when the condition is signaled. > > How could I arrange this? There is no MESSAGE slot, but there is a FORMAT-CONTROL slot, which should amount to the same thing, if you don't supply any FORMAT- ARGUMENTS. There is a CAUSE slot, but the code that does the signalling in Java.java needs to be changed to initialize that slot when the condition object is constructed, unless it's constructed by the JavaException constructor, which is not called for subclasses of JavaException defined by DEFINE-CONDITION. There's a fundamental (and, I think, necessary) schizophrenia in ABCL's condition system: conditions defined in the *.java source files are instanceof Condition, but conditions defined by DEFINE-CONDITION are normal STANDARD-OBJECTs. Something along the lines of (completely untested): catch (Throwable t) { Class tClass = t.getClass(); Symbol condition = getCondition(t.getClass()); if (condition == null) // The cause slot gets initialized by the JavaException // constructor here, since we're calling it directly. signal(new JavaException(t)); else // But here you have to do it by hand, since we're really // constructing a STANDARD-OBJECT. //signal(condition, new SimpleString(getMessage(t))); Symbol.SIGNAL.execute( condition, Keyword.CAUSE, new JavaObject(t), Keyword.FORMAT_CONTROL, new SimpleString(getMessage(t))); } In the second case, you probably also want to verify that the condition you're about to signal is a subclass of JAVA-EXCEPTION before you pass it the :CAUSE initarg, since otherwise it won't have that slot. I also changed the registered exception map to be a normal HashMap. Initially I did this because I was trying to pin down some non- deterministic behavior involving the string that gets returned by getMessage(t), but it turns out that the non-determinism is caused by HotSpot's just-in-time compilation of the code in question. I don't think we need a WeakHashMap in any case, since the map is never going to be very big, and in most cases everything in it will be hanging around for other reasons anyway. -Peter |
From: Andras S. <as...@ma...> - 2005-11-06 18:52:13
|
On Fri, 4 Nov 2005, Peter Graves wrote: > > There's a fundamental (and, I think, necessary) schizophrenia in ABCL's > condition system: conditions defined in the *.java source files are > instanceof Condition, but conditions defined by DEFINE-CONDITION are > normal STANDARD-OBJECTs. > Is this the reason for the following? CL-USER(1): (define-condition throwable (java-exception) ()) THROWABLE CL-USER(2): (register-java-exception "java.lang.Throwable" 'throwable) T CL-USER(3): (handler-case (jnew (jconstructor "java.lang.String" "java.lang.String") (make-immediate-object nil :ref)) (throwable (c) c)) #<THROWABLE {F1CDFB}> CL-USER(4): (java-exception-cause *) Debugger invoked on condition of type TYPE-ERROR: The value #<THROWABLE {F1CDFB}> is not of type JAVA-EXCEPTION. Restarts: 0: TOP-LEVEL Return to top level. [1] CL-USER(5): :res CL-USER(6): (typep * 'java-exception) T CL-USER(7): That there is an error is fine, since I haven't updated Java.java. (I plan to do that soon, by the way.) But the message is quite misleading. Andras |
From: Andras S. <as...@ma...> - 2005-11-07 00:29:47
|
On Fri, 4 Nov 2005, Peter Graves wrote: > > Something along the lines of (completely untested): > > catch (Throwable t) { > Class tClass = t.getClass(); > Symbol condition = getCondition(t.getClass()); > if (condition == null) > // The cause slot gets initialized by the JavaException > // constructor here, since we're calling it directly. > signal(new JavaException(t)); > else > // But here you have to do it by hand, since we're really > // constructing a STANDARD-OBJECT. > //signal(condition, new SimpleString(getMessage(t))); > Symbol.SIGNAL.execute( > condition, > Keyword.CAUSE, > new JavaObject(t), > Keyword.FORMAT_CONTROL, > new SimpleString(getMessage(t))); > } It's tested now :) > > In the second case, you probably also want to verify that the condition > you're about to signal is a subclass of JAVA-EXCEPTION before you pass > it the :CAUSE initarg, since otherwise it won't have that slot. Perhaps the best place for this check would be in Java.getCondition(). In any case, I could do with some help on how to do this, because I don't even know to get the condition associated with a symbol on the Java side. Andras |
From: Peter G. <pe...@ar...> - 2005-11-07 00:53:12
|
On Mon, 7 Nov 2005 at 01:29:37 +0100, Andras Simon wrote: > On Fri, 4 Nov 2005, Peter Graves wrote: > > In the second case, you probably also want to verify that the condition > > you're about to signal is a subclass of JAVA-EXCEPTION before you pass > > it the :CAUSE initarg, since otherwise it won't have that slot. > > Perhaps the best place for this check would be in Java.getCondition(). > In any case, I could do with some help on how to do this, because I > don't even know to get the condition associated with a symbol on the > Java side. Suppose you've done (for example): (in-package #:cl-user) (define-condition throwable (java-exception) ()) You can then use MAKE-CONDITION to get a condition instance: (make-condition 'throwable) The same thing in Java would be: LispObject condition = Symbol.MAKE_CONDITION.execute(PACKAGE_CL_USER.intern("THROWABLE")); Or, if what you want is the condition class, rather than an instance: LispClass c = LispClass.findClass(PACKAGE_CL_USER.intern("THROWABLE")); BTW, in Java.getCondition(), it looks like you might be able to save a call: for (Class c = cl ; c != o ; c = c.getSuperclass()) if (registeredExceptions.containsKey(c)) return (Symbol)registeredExceptions.get(c); return null; I think this could be: for (Class c = cl ; c != o ; c = c.getSuperclass()) { Object object = registeredExceptions.get(c); if (object != null) return (Symbol) object; } return null; Once again, completely untested... :) -Peter |
From: Andras S. <as...@ma...> - 2005-11-07 17:46:10
|
On Sun, 6 Nov 2005, Peter Graves wrote: > Suppose you've done (for example): > > (in-package #:cl-user) > (define-condition throwable (java-exception) ()) > > You can then use MAKE-CONDITION to get a condition instance: > > (make-condition 'throwable) > > The same thing in Java would be: > > LispObject condition = > Symbol.MAKE_CONDITION.execute(PACKAGE_CL_USER.intern("THROWABLE")); > > Or, if what you want is the condition class, rather than an instance: > > LispClass c = > LispClass.findClass(PACKAGE_CL_USER.intern("THROWABLE")); Yes, this last one was the bit I needed. Thanks! > > BTW, in Java.getCondition(), it looks like you might be able to save a > call: > > for (Class c = cl ; c != o ; c = c.getSuperclass()) > if (registeredExceptions.containsKey(c)) > return (Symbol)registeredExceptions.get(c); > return null; > > I think this could be: > > for (Class c = cl ; c != o ; c = c.getSuperclass()) { > Object object = registeredExceptions.get(c); > if (object != null) > return (Symbol) object; > } > return null; This is how it is now, as it looks more natural now that I also check whether object is a subclass of JAVA-EXCEPTION. The code that does the checking isn't very pretty. Some excuses: - I'm sure there is a standard way to check (in Java) whether one (Lisp) class is a subclass of another, but I couldn't find it. - NIL is not a Cons, and that makes going down a list a bit harder than usual. - I would've liked to have a private static final LispClass java_exception = LispClass.findClass(Symbol.JAVA_EXCEPTION); to compare the superclasses of the condition to be signaled with, but it got initialized too early (?) and ended up being null. So now java_exception is a local variable in isJavaException [a misleading name, by the way]. Maybe it would be simpler to check the name of these classes against Symbol.JAVA_EXCEPTION, but that would mean slightly more work at runtime. > > Once again, completely untested... :) ... but working :) Andras |
From: Andras S. <as...@ma...> - 2005-10-29 00:30:22
|
[Sorry for the late reply; my adsl modem gave up the ghost after a power outage, and it took two days to get a replacement.] On Thu, 27 Oct 2005, Peter Graves wrote: > Suppose (for the sake of argument) you do: > > (define-condition throwable (java-exception) ()) > (register-java-exception "java.lang.Throwable" 'throwable) > > And then some call to Java throws a NullPointerException (for example). > > Now, you haven't registered "java.lang.NullPointerException". But from > Java's point of view, a NullPointerException _is_ a Throwable, so the > condition registered for "java.lang.Throwable" should arguably be > signalled. > > You can't accomplish this with a simple hashtable lookup of > "java.lang.NullPointerException". You'd have to walk the list of > registered exceptions and check to see if the class of the exception at > hand is either identical to, or a subclass of, one of the registered > exception classes. And the order in which you walked the list would > matter, in exactly the same way the order of catch clauses matters > after a try block in Java code. How about walking the list of superclasses of the exception thrown (starting with itself of course), and stop at the first that is registered? Andras |
From: Andras S. <as...@ma...> - 2005-10-29 13:50:44
|
On Sat, 29 Oct 2005, Andras Simon wrote: > On Thu, 27 Oct 2005, Peter Graves wrote: > >> Suppose (for the sake of argument) you do: >> >> (define-condition throwable (java-exception) ()) >> (register-java-exception "java.lang.Throwable" 'throwable) >> >> And then some call to Java throws a NullPointerException (for example). >> >> Now, you haven't registered "java.lang.NullPointerException". But from >> Java's point of view, a NullPointerException _is_ a Throwable, so the >> condition registered for "java.lang.Throwable" should arguably be >> signalled. >> >> You can't accomplish this with a simple hashtable lookup of >> "java.lang.NullPointerException". You'd have to walk the list of >> registered exceptions and check to see if the class of the exception at >> hand is either identical to, or a subclass of, one of the registered >> exception classes. And the order in which you walked the list would >> matter, in exactly the same way the order of catch clauses matters >> after a try block in Java code. > > How about walking the list of superclasses of the exception thrown > (starting with itself of course), and stop at the first that is > registered? I committed some changes (for JNEW only) in this spirit, so now we have CL-USER> (define-condition throwable (java-exception) ()) THROWABLE CL-USER> (register-java-exception "java.lang.Throwable" 'throwable) T CL-USER> (handler-case (jnew (jconstructor "java.lang.String" "java.lang.String") (make-immediate-object nil :ref)) (throwable () 'throwable)) THROWABLE CL-USER> (define-condition null-pointer-exception (throwable) ()) NULL-POINTER-EXCEPTION CL-USER> (register-java-exception "java.lang.NullPointerException" 'null-pointer-exception) T CL-USER> (handler-case (jnew (jconstructor "java.lang.String" "java.lang.String") (make-immediate-object nil :ref)) (throwable () 'throwable)) THROWABLE CL-USER> (handler-case (jnew (jconstructor "java.lang.String" "java.lang.String") 42) (null-pointer-exception () 'null-pointer-exception) (throwable () 'throwable)) THROWABLE CL-USER> (handler-case (jnew (jconstructor "java.lang.String" "java.lang.String") (make-immediate-object nil :ref)) (null-pointer-exception () 'null-pointer-exception) (throwable () 'throwable)) NULL-POINTER-EXCEPTION CL-USER> Andras |
From: Peter G. <pe...@ar...> - 2005-10-30 10:37:32
|
On Sat, 29 Oct 2005 at 15:50:31 +0200, Andras Simon wrote: > I committed some changes (for JNEW only) in this spirit, so now we > have > > CL-USER> (define-condition throwable (java-exception) ()) > THROWABLE > CL-USER> (register-java-exception "java.lang.Throwable" 'throwable) > T > CL-USER> (handler-case > (jnew (jconstructor "java.lang.String" "java.lang.String") > (make-immediate-object nil :ref)) > (throwable () 'throwable)) > THROWABLE > CL-USER> (define-condition null-pointer-exception (throwable) ()) > NULL-POINTER-EXCEPTION > CL-USER> (register-java-exception "java.lang.NullPointerException" > 'null-pointer-exception) T CL-USER> (handler-case > (jnew (jconstructor "java.lang.String" "java.lang.String") > (make-immediate-object nil :ref)) > (throwable () 'throwable)) > THROWABLE > CL-USER> (handler-case > (jnew (jconstructor "java.lang.String" "java.lang.String") 42) > (null-pointer-exception () 'null-pointer-exception) > (throwable () 'throwable)) > THROWABLE > CL-USER> (handler-case > (jnew (jconstructor "java.lang.String" "java.lang.String") > (make-immediate-object nil :ref)) > (null-pointer-exception () 'null-pointer-exception) > (throwable () 'throwable)) > NULL-POINTER-EXCEPTION > CL-USER> Looks good. -Peter |
From: Andras S. <as...@ma...> - 2005-10-30 10:49:53
|
On Sun, 30 Oct 2005, Peter Graves wrote: > On Sat, 29 Oct 2005 at 15:50:31 +0200, Andras Simon wrote: >> I committed some changes (for JNEW only) in this spirit, so now we >> have >> >> CL-USER> (define-condition throwable (java-exception) ()) >> THROWABLE >> CL-USER> (register-java-exception "java.lang.Throwable" 'throwable) >> T >> CL-USER> (handler-case >> (jnew (jconstructor "java.lang.String" "java.lang.String") >> (make-immediate-object nil :ref)) >> (throwable () 'throwable)) >> THROWABLE >> CL-USER> (define-condition null-pointer-exception (throwable) ()) >> NULL-POINTER-EXCEPTION >> CL-USER> (register-java-exception "java.lang.NullPointerException" >> 'null-pointer-exception) T CL-USER> (handler-case >> (jnew (jconstructor "java.lang.String" "java.lang.String") >> (make-immediate-object nil :ref)) >> (throwable () 'throwable)) >> THROWABLE >> CL-USER> (handler-case >> (jnew (jconstructor "java.lang.String" "java.lang.String") 42) >> (null-pointer-exception () 'null-pointer-exception) >> (throwable () 'throwable)) >> THROWABLE >> CL-USER> (handler-case >> (jnew (jconstructor "java.lang.String" "java.lang.String") >> (make-immediate-object nil :ref)) >> (null-pointer-exception () 'null-pointer-exception) >> (throwable () 'throwable)) >> NULL-POINTER-EXCEPTION >> CL-USER> > > Looks good. In the meantime I changed all the other Java calling functions, not just JNEW, to use the new scheme. And there are a few related tests in tests/java-tests.lisp. Thanks for pointing out this problem! Andras |
From: Peter G. <pe...@ar...> - 2005-10-30 11:48:00
|
On Sun, 30 Oct 2005 at 11:49:46 +0100, Andras Simon wrote: > In the meantime I changed all the other Java calling functions, not > just JNEW, to use the new scheme. And there are a few related tests > in tests/java-tests.lisp. Thanks for doing the tests! I moved WITH-REGISTERED-EXCEPTION from test-utilities.lisp to java- tests.lisp and #+abcl'ed it, since Allegro runs java-tests.lisp too. ABCL's cross-implementation test suite is very new, and I haven't really got the infrastructure 100% nailed down yet, but in general, things should only go in test-utilities.lisp if they're used by tests in all (or at least most) of the tested areas. Helper functions and macros that are used in only one of the test files should just go in that particular test file. By the way, I like the idea of WITH-REGISTERED-EXCEPTION, and if we keep going in this direction, we should probably just put it in java.lisp. Or should it be WITH-REGISTERED-EXCEPTIONS, allowing you to specify multiple registrations at once: (with-registered-exceptions (("java.lang.Throwable" 'throwable) ("java.lang.NullPointerException 'null-pointer-exception)) (do-something)) -Peter |
From: Andras S. <as...@ma...> - 2005-10-30 12:19:16
|
On Sun, 30 Oct 2005, Peter Graves wrote: > On Sun, 30 Oct 2005 at 11:49:46 +0100, Andras Simon wrote: >> In the meantime I changed all the other Java calling functions, not >> just JNEW, to use the new scheme. And there are a few related tests >> in tests/java-tests.lisp. > > Thanks for doing the tests! > > I moved WITH-REGISTERED-EXCEPTION from test-utilities.lisp to java- > tests.lisp and #+abcl'ed it, since Allegro runs java-tests.lisp too. > > ABCL's cross-implementation test suite is very new, and I haven't > really got the infrastructure 100% nailed down yet, but in general, > things should only go in test-utilities.lisp if they're used by tests > in all (or at least most) of the tested areas. > > Helper functions and macros that are used in only one of the test files > should just go in that particular test file. I'll try to remember (and adhere to) this! > By the way, I like the idea of WITH-REGISTERED-EXCEPTION, and if we > keep going in this direction, we should probably just put it in > java.lisp. > > Or should it be WITH-REGISTERED-EXCEPTIONS, allowing you to specify > multiple registrations at once: > > (with-registered-exceptions > (("java.lang.Throwable" 'throwable) > ("java.lang.NullPointerException 'null-pointer-exception)) > (do-something)) If something like it ever gets in java.lisp, it should definitely take this form. But I don't see any general use for it. Do you? If it also saved and restored the previous state, that would seem more useful, but I'm afraid it'd also be a step in the direction we agreed not to go... Andras |
From: Peter G. <pe...@ar...> - 2005-10-30 12:26:17
|
On Sun, 30 Oct 2005 at 13:19:05 +0100, Andras Simon wrote: > > By the way, I like the idea of WITH-REGISTERED-EXCEPTION, and if we > > keep going in this direction, we should probably just put it in > > java.lisp. > > > > Or should it be WITH-REGISTERED-EXCEPTIONS, allowing you to specify > > multiple registrations at once: > > > > (with-registered-exceptions > > (("java.lang.Throwable" 'throwable) > > ("java.lang.NullPointerException 'null-pointer-exception)) > > (do-something)) > > If something like it ever gets in java.lisp, it should definitely take > this form. But I don't see any general use for it. Do you? If it also > saved and restored the previous state, that would seem more useful, but > I'm afraid it'd also be a step in the direction we agreed not to go... Good point. Thanks for reminding me! I think my jury is still out on a lot of this stuff, actually. That might be one of the reasons I keep forgetting our previous conclusions. (Old age is definitely a more important reason, however.) In any case, we can leave WITH-REGISTERED-EXCEPTIONS in java-tests.lisp for now. -Peter |