* Question on language design (keywords vs Pervasives) @ 2000-08-18 2:07 Fermin Reig 2000-08-19 16:57 ` Frank Atanassow 2000-08-20 19:01 ` Pierre Weis 0 siblings, 2 replies; 13+ messages in thread From: Fermin Reig @ 2000-08-18 2:07 UTC (permalink / raw) To: caml-list Hi, I'm curious about some interesting language design choices in ocaml 3.0. * "raise", "exn" are not keywords, but definitions in the Pervasives module. This means that I can rebind them, for ex., like this: # type exn = char;; type exn = char # let raise x = x + 1;; val raise : int -> int = <fun> Similarly for other types in the Pervasives module, like int, etc. (However, "exception", for declaring a new exception is a reserved word). I can speculate that the intention is precisely that praogrammers be able to rebind them at will, or maybe that it simplifies implementing interpreters/compilers, but I don't know for sure. Could anyone (preferably someone involved in the design) comment on the rationale for these choices? Thanks, Fermin Reig ------------------------------------------------------ Department of Computing Science, University of Glasgow http://www.dcs.gla.ac.uk/~reig ^ permalink raw reply [flat|nested] 13+ messages in thread
* Question on language design (keywords vs Pervasives) 2000-08-18 2:07 Question on language design (keywords vs Pervasives) Fermin Reig @ 2000-08-19 16:57 ` Frank Atanassow 2000-08-20 19:01 ` Pierre Weis 1 sibling, 0 replies; 13+ messages in thread From: Frank Atanassow @ 2000-08-19 16:57 UTC (permalink / raw) To: reig; +Cc: caml-list Fermin Reig writes: > I'm curious about some interesting language design choices in ocaml > 3.0. > > * "raise", "exn" are not keywords, but definitions in the Pervasives module. > > This means that I can rebind them, [..elided..] > > I can speculate that the intention is precisely that praogrammers be > able to rebind them at will, or maybe that it simplifies implementing > interpreters/compilers, but I don't know for sure. Could anyone > (preferably someone involved in the design) comment on the rationale > for these choices? Maybe the ability to rebind was some small motivation, but I imagine the goal of simplicity was the more significant factor. Why make "int" or "raise" a keyword if you don't need to? Even if you rebind "int", say, functions operating on the new "int" will not work on the old. Conversely, if you made "int" or "raise" a keyword, why stop there? You could also make a whole range of other notions special: reals, complex numbers, associative maps, commands (procedures with types of the form A -> unit), file I/O primitives, regular expressions, certain shell-related procedures... maybe you can guess where I'm heading. :) Of course, it's true OTOH that as keywords we could be slightly more confident that we haven't made a mistake and overlooked some rebinding, but in practice most people leave "int" and "raise" alone, or if they're rebound, then that's done in another module and the fact that we're not talking about Pervasives.int, say, is explicit in the fact that we call it "ModuleX.int", say. (BTW, I'm not involved with Ocaml.) -- Frank Atanassow, Dept. of Computer Science, Utrecht University Padualaan 14, PO Box 80.089, 3508 TB Utrecht, Netherlands Tel +31 (030) 253-1012, Fax +31 (030) 251-3791 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Question on language design (keywords vs Pervasives) 2000-08-18 2:07 Question on language design (keywords vs Pervasives) Fermin Reig 2000-08-19 16:57 ` Frank Atanassow @ 2000-08-20 19:01 ` Pierre Weis 2000-08-20 19:55 ` John Prevost 2000-08-21 16:44 ` John Max Skaller 1 sibling, 2 replies; 13+ messages in thread From: Pierre Weis @ 2000-08-20 19:01 UTC (permalink / raw) To: reig; +Cc: caml-list > I'm curious about some interesting language design choices in ocaml > 3.0. > > * "raise", "exn" are not keywords, but definitions in the Pervasives module. > > This means that I can rebind them, for ex., like this: [...] > Similarly for other types in the Pervasives module, like int, > etc. (However, "exception", for declaring a new exception is a > reserved word). You encounter here the border between syntax, language design choices and semantics: ``exception'' must be a keyword, since it introduces a syntactic construct (precisely the addition of a new constructor to the predefined type exn: ident of type). On the other hand, ``raise'' does not introduce a syntactic construct since exception raising is parsed as a regular application (application of the identifier raise to an exception value). Hence, strictly speaking, raise has not to be a keyword. However there are two good reasons to turn raise into a keyword: 1) To prevent the redefinition of the predefined raise primitive. 2) To parse the exception raising slightly differently than the regular application: for instance, we could spare some parentheses in case of a functional exception constructor, and write raise Invalid_argument "divide" instead of raise (Invalid_Argument "divide"). This is as reasonable as the current syntactic status of raise: indeed, this scheme has been used in Caml for a long time. > I can speculate that the intention is precisely that praogrammers be > able to rebind them at will, or maybe that it simplifies implementing > interpreters/compilers, but I don't know for sure. Could anyone > (preferably someone involved in the design) comment on the rationale > for these choices? > > Thanks, > > Fermin Reig > > ------------------------------------------------------ > Department of Computing Science, University of Glasgow > http://www.dcs.gla.ac.uk/~reig The ``users can rebind'' argument is definitively what we intended when we decided to allow the rebinding of usual operators (infix or prefix symbols, such as +, -, *, ...). For ``raise'' this is not so clear, since redefining ``raise'' is a very bad idea to obtain a readable Caml program. Anyway, this treatment of ``raise'' saved one or 2 lines in the parser of the language, and several characters in the lexer definition. Long time ago, we were hesitating before addding that little amount of code to the compiler. Now that the parser has become considerably bigger, we may give it a second thought! In particular, if we consider that knowing for sure that ``raise'' indeed raises exceptions is important for the programmer... (and probably for automatic tools that can try to analyse exception handling in Caml programs). Pierre Weis INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://cristal.inria.fr/~weis/ ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Question on language design (keywords vs Pervasives) 2000-08-20 19:01 ` Pierre Weis @ 2000-08-20 19:55 ` John Prevost 2000-08-21 8:58 ` Pierre Weis 2000-08-21 16:44 ` John Max Skaller 1 sibling, 1 reply; 13+ messages in thread From: John Prevost @ 2000-08-20 19:55 UTC (permalink / raw) To: Pierre Weis; +Cc: reig, caml-list >>>>> "pw" == Pierre Weis <Pierre.Weis@inria.fr> writes: pw> On the other hand, ``raise'' does not introduce a syntactic pw> construct since exception raising is parsed as a regular pw> application (application of the identifier raise to an pw> exception value). Hence, strictly speaking, raise has not to pw> be a keyword. However there are two good reasons to turn raise pw> into a keyword: pw> 1) To prevent the redefinition of the predefined raise pw> primitive. pw> 2) To parse the exception raising slightly pw> differently than the regular application: for instance, we pw> could spare some parentheses in case of a functional exception pw> constructor, and write raise Invalid_argument "divide" instead pw> of raise (Invalid_Argument "divide"). pw> This is as reasonable as the current syntactic status of pw> raise: indeed, this scheme has been used in Caml for a long pw> time. On the other hand, allowing raise to be redefined has the advantage that raise could be replaced with a new function of the same type that does some extra work and then calls raise normally. I can't think of a really good example at the moment, though. My personal feeling is that it's good for the design of a language to make as few things keywords as possible. For an example of too many keywords, see SQL, where the definition of the language not only reserves many many words, but also provides a list of possible future keywords (and mentions that this list is not exhaustive.) SQL does, however, provide a way to escape identifiers which would otherwise conflict with reserved words. John. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Question on language design (keywords vs Pervasives) 2000-08-20 19:55 ` John Prevost @ 2000-08-21 8:58 ` Pierre Weis 2000-08-21 19:47 ` John Prevost 0 siblings, 1 reply; 13+ messages in thread From: Pierre Weis @ 2000-08-21 8:58 UTC (permalink / raw) To: John Prevost; +Cc: caml-list > On the other hand, allowing raise to be redefined has the advantage > that raise could be replaced with a new function of the same type that > does some extra work and then calls raise normally. I can't think of > a really good example at the moment, though. You're right, there is no really good example that uses redefinition of raise. That's why the advantage to be able to redefine it may overcome the inconvenience of not being always sure of its meaning. > My personal feeling is that it's good for the design of a language to > make as few things keywords as possible. For an example of too many > keywords, see SQL, where the definition of the language not only > reserves many many words, but also provides a list of possible future > keywords (and mentions that this list is not exhaustive.) SQL does, > however, provide a way to escape identifiers which would otherwise > conflict with reserved words. > > John. You're right, we don't want to have zillions of keywords. On the other hand, you also need to have some level of confidence into the words you use in the language, otherwise you can write horrors as the famous if else then else else then when then and else are not reserved. Pierre Weis INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://cristal.inria.fr/~weis/ ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Question on language design (keywords vs Pervasives) 2000-08-21 8:58 ` Pierre Weis @ 2000-08-21 19:47 ` John Prevost 2000-08-21 21:41 ` Pierre Weis 0 siblings, 1 reply; 13+ messages in thread From: John Prevost @ 2000-08-21 19:47 UTC (permalink / raw) To: Pierre Weis; +Cc: John Prevost, caml-list >>>>> "pw" == Pierre Weis <Pierre.Weis@inria.fr> writes: pw> You're right, there is no really good example that uses pw> redefinition of raise. That's why the advantage to be able to pw> redefine it may overcome the inconvenience of not being always pw> sure of its meaning. Actually, I just thought of one. :) If you redefine raise in a special way, you could have it report that it was raising exceptions, even if those exceptions are later caught. Might be good for analyzing your code. pw> You're right, we don't want to have zillions of keywords. On pw> the other hand, you also need to have some level of confidence pw> into the words you use in the language, otherwise you can pw> write horrors as the famous pw> if else then else else then pw> when then and else are not reserved. Right. But I don't think this is necessarily the case for raise. I just gave a good example above. There's also the possibility of somebody who could really care less about raising exceptions most of the time (e.g. me) but who has some code which performs an operation named "raise". In that context, having to fight the system to get around it is bad. There's always a tension here. For example, when I'm writing PL implementations, the fact that "type" is a keyword is rather upsetting. But, I can deal--especially because I know that O'Caml doesn't have that many gratuitous keywords--everything's there for a reason. John. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Question on language design (keywords vs Pervasives) 2000-08-21 19:47 ` John Prevost @ 2000-08-21 21:41 ` Pierre Weis 0 siblings, 0 replies; 13+ messages in thread From: Pierre Weis @ 2000-08-21 21:41 UTC (permalink / raw) To: John Prevost; +Cc: caml-list > >>>>> "pw" == Pierre Weis <Pierre.Weis@inria.fr> writes: > > pw> You're right, there is no really good example that uses > pw> redefinition of raise. That's why the advantage to be able to > pw> redefine it may overcome the inconvenience of not being always > pw> sure of its meaning. > > Actually, I just thought of one. :) If you redefine raise in a > special way, you could have it report that it was raising exceptions, > even if those exceptions are later caught. Might be good for > analyzing your code. Mm. I don't think it could be considered ``good for analyzing your code'' if you compare to real tools such as the replay debugger (dynamic analysis) or Francois Pessaux's exception analyzer (static analysis). > pw> You're right, we don't want to have zillions of keywords. On > pw> the other hand, you also need to have some level of confidence > pw> into the words you use in the language, otherwise you can > pw> write horrors as the famous > > pw> if else then else else then > > pw> when then and else are not reserved. > > Right. But I don't think this is necessarily the case for raise. I > just gave a good example above. There's also the possibility of > somebody who could really care less about raising exceptions most of > the time (e.g. me) but who has some code which performs an operation > named "raise". In that context, having to fight the system to get > around it is bad. But reading code that uses ``raise'' all over the place to do many things other than raising exceptions could also be extreamely confusing... > There's always a tension here. For example, when I'm writing PL > implementations, the fact that "type" is a keyword is rather > upsetting. But, I can deal--especially because I know that O'Caml > doesn't have that many gratuitous keywords--everything's there for a > reason. > > John. Exactly, that's why I explained the reasons why we used to have raise as a keyword, just to get a cleaner language: nothing gratuitous here, the notion of exception raising is considered important and worth a keyword to handle them (try) and a keyword to throw them (raise). Pierre Weis INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://cristal.inria.fr/~weis/ ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Question on language design (keywords vs Pervasives) 2000-08-20 19:01 ` Pierre Weis 2000-08-20 19:55 ` John Prevost @ 2000-08-21 16:44 ` John Max Skaller 2000-08-21 21:24 ` Pierre Weis 1 sibling, 1 reply; 13+ messages in thread From: John Max Skaller @ 2000-08-21 16:44 UTC (permalink / raw) To: Pierre Weis; +Cc: reig, caml-list Pierre Weis wrote: > The ``users can rebind'' argument is definitively what we intended > when we decided to allow the rebinding of usual operators (infix or > prefix symbols, such as +, -, *, ...). For ``raise'' this is not so > clear, since redefining ``raise'' is a very bad idea to obtain a > readable Caml program. I'm not sure I agree with that. If raise is the _standard_ way to raise an exception, then it _should_ be rebindable (and be defined in terms of a more primitive function). The reason is precisely to permit hooking it by the user, which is an extremely common requirement. For example, to introduce some extra logging. In C++, exceptions are raise by a keyword 'throw', and it is a pain, because good practice dictates NOT to ever raise an exception directly with 'throw', but to call a (template) function usually defined to simply raise the exception (using throw). This permits replacing the function to, for example, print an error message to stderr, as well as throwing the exception. The problem is, this doesn't work for any third party code, or even one's own code, if the idea occurs to one belatedly. -- John (Max) Skaller, mailto:skaller@maxtal.com.au 10/1 Toxteth Rd Glebe NSW 2037 Australia voice: 61-2-9660-0850 checkout Vyper http://Vyper.sourceforge.net download Interscript http://Interscript.sourceforge.net ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Question on language design (keywords vs Pervasives) 2000-08-21 16:44 ` John Max Skaller @ 2000-08-21 21:24 ` Pierre Weis 2000-08-22 0:38 ` Kwangkeun Yi 0 siblings, 1 reply; 13+ messages in thread From: Pierre Weis @ 2000-08-21 21:24 UTC (permalink / raw) To: John Max Skaller; +Cc: caml-list > I'm not sure I agree with that. If raise is the _standard_ > way to raise an exception, then it _should_ be rebindable (and be > defined in terms of a more primitive function). I'm sure that there is no ``more primitive function'' than raise to raise an exception. So sorry, you cannot define raise ``in terms of a more primitive function'' in Caml. You would need a language with call/cc to express that, and Caml is not this language. > The reason is precisely to permit hooking it by the user, which is > an extremely common requirement. > For example, to introduce some extra logging. Nobody never asked for that for more than 9 years before raise has been turned into a regular ident to save 2 lines in the Caml parser. So, no, this is not ``an extremely common requirement''. > In C++, exceptions are raise by a keyword 'throw', and it > is a pain, because good practice dictates NOT to ever raise an > exception directly with 'throw', but to call a (template) function > usually defined to simply raise the exception (using throw). > This permits replacing the function to, for example, print an > error message to stderr, as well as throwing the exception. > The problem is, this doesn't work for any third party code, > or even one's own code, if the idea occurs to one belatedly. > > -- > John (Max) Skaller, mailto:skaller@maxtal.com.au > 10/1 Toxteth Rd Glebe NSW 2037 Australia voice: 61-2-9660-0850 > checkout Vyper http://Vyper.sourceforge.net > download Interscript http://Interscript.sourceforge.net There is a confusion here: Objective Caml is not C++, despite the Objective qualifier: there is no template in the language, so you cannot use them for exceptions. Also remember that in Caml exceptions are used in common programming situations where raising an exception is not an error but a success: for instance, one commonly raises the predefined exception Exit to exit from a while loop, or raises a user's defined exception to jump out and carry the final result of an expression (e.g. if Break has type int -> exn, you can raise (Break v) to exit from a for loop, returning the integer result v to the surrounding try with). The tracing mechanism you described would be strange in this kind of situation. Also, the exception tracing problem solved by this kind of hacks is handled more cleanly and elegantly by the replay debugger of Objective Caml, that permits to go back to the point where the exception has been raised and to examine the local environment. On the other hand, you can use the same encapsulation techniques in Caml and to define and use specialized functions to raise specialized exceptions, and this is considered good practice (e.g. predefined exception raisers invalid_arg or failwith). I was just arguing the usefulness of being able to redefine the meaning of raise to something unrelated to raising exceptions, I was not un any extent proposing to restrict the use of raise into whatever function you need to; I agree with you on this point, we want to be able to define specialized exception raisers. I was just saying that (to me) the program fragment if x = 0 then raise (Division_by_zero) else 1 / x should raise the exception Division_by_zero, when x = 0 is verified. I would be glad if Caml could ensure that property in any context. Conversely, I would consider it as an undesirable feature if this expression could return something else in some context; for instance, because somewhere raise has been rebound as a constant polymorphic function: let raise _ = 1;; Pierre Weis INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://cristal.inria.fr/~weis/ ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Question on language design (keywords vs Pervasives) 2000-08-21 21:24 ` Pierre Weis @ 2000-08-22 0:38 ` Kwangkeun Yi 2000-08-22 2:25 ` John Max Skaller 2000-08-22 8:31 ` Pierre Weis 0 siblings, 2 replies; 13+ messages in thread From: Kwangkeun Yi @ 2000-08-22 0:38 UTC (permalink / raw) To: Pierre.Weis; +Cc: skaller, caml-list > I'm sure that there is no ``more primitive function'' than raise to > raise an exception. So sorry, you cannot define raise ``in terms of a > more primitive function'' in Caml. You would need a language with > call/cc to express that, and Caml is not this language. To make it precise, we don't even need call/cc. Just a kind of cps transformation that carries two continuations (one for normal continuation and the other for handler continuation) removes all the raise/try expressions. The transformation is well-known. See @InProceedings{KiYiDa98, author = "Jung-taek Kim and Kwangkeun Yi and Olivier Danvy", title = "Assessing the Overhead of ML Exceptions by Selective CPS Transformation", pages = "103-114", booktitle = "The Proceedings of the ACM SIGPLAN Workshop on ML", year = 1998, url = "http://ropas.kaist.ac.kr/~kwang/paper/98-ml-kiyida.ps.gz", month = sep } -Kwang -- Kwangkeun Yi http://cs.kaist.ac.kr/~kwang ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Question on language design (keywords vs Pervasives) 2000-08-22 0:38 ` Kwangkeun Yi @ 2000-08-22 2:25 ` John Max Skaller 2000-08-22 9:08 ` Pierre Weis 2000-08-22 8:31 ` Pierre Weis 1 sibling, 1 reply; 13+ messages in thread From: John Max Skaller @ 2000-08-22 2:25 UTC (permalink / raw) Cc: Pierre.Weis, caml-list Pierre wrote: > I'm sure that there is no ``more primitive function'' than raise to > raise an exception. So sorry, you cannot define raise ``in terms of a > more primitive function'' in Caml. Perhaps my intent was not understood. The idea is to provide a primitive '_raise' construction, but provide a wrapper function 'raise' in the standard library which does nothing but call _raise: let raise ex = _raise ex which allows the raise function to be rebound by the client, catching all exceptions raised using the 'raise' function in those sources where the client has in fact rebound 'raise' before use. Naturally, this will not affect (compiled) library code unless it, too, is recompiled, so not all exceptions are trapped this way. This can be done right now by the client, simply defining let raise' ex = raise ex even if raise is a primitive construction, provided that the source module uses raise' everywhere, rather than raise. So it can be done now, by search and replace of raise by raise', which is not really much harder than rebinding. -- John (Max) Skaller, mailto:skaller@maxtal.com.au 10/1 Toxteth Rd Glebe NSW 2037 Australia voice: 61-2-9660-0850 checkout Vyper http://Vyper.sourceforge.net download Interscript http://Interscript.sourceforge.net ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Question on language design (keywords vs Pervasives) 2000-08-22 2:25 ` John Max Skaller @ 2000-08-22 9:08 ` Pierre Weis 0 siblings, 0 replies; 13+ messages in thread From: Pierre Weis @ 2000-08-22 9:08 UTC (permalink / raw) To: John Max Skaller; +Cc: caml-list > Pierre wrote: > > > I'm sure that there is no ``more primitive function'' than raise to > > raise an exception. So sorry, you cannot define raise ``in terms of a > > more primitive function'' in Caml. > > Perhaps my intent was not understood. The idea is to provide > a primitive '_raise' construction, but provide a wrapper function > 'raise' in the standard library which does nothing but call _raise: > > let raise ex = _raise ex > [...] Thank you for your explanation: I can now explain the issue I was addressing using your own terminology. I was addressing the meaning of the basic exception raiser, the very primitive that you named here the "primitive '_raise' construction"; I think that the meaning of this primitive should be fixed once and for all, and the simplest way to do so is to turn out its name into a keyword. (Hence, if we still give to this primitive its usual name, it suggests to turn ``raise'' into a keyword; if we use your naming convention then ``_raise'' should be turned into a keyword.) Pierre Weis INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://cristal.inria.fr/~weis/ ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Question on language design (keywords vs Pervasives) 2000-08-22 0:38 ` Kwangkeun Yi 2000-08-22 2:25 ` John Max Skaller @ 2000-08-22 8:31 ` Pierre Weis 1 sibling, 0 replies; 13+ messages in thread From: Pierre Weis @ 2000-08-22 8:31 UTC (permalink / raw) To: Kwangkeun Yi; +Cc: caml-list > > I'm sure that there is no ``more primitive function'' than raise to > > raise an exception. So sorry, you cannot define raise ``in terms of a > > more primitive function'' in Caml. You would need a language with > > call/cc to express that, and Caml is not this language. > > To make it precise, we don't even need call/cc. > Just a kind of cps transformation that carries two continuations (one > for normal continuation and the other for handler continuation) > removes all the raise/try expressions. The transformation is > well-known. See > > @InProceedings{KiYiDa98, > author = "Jung-taek Kim and Kwangkeun Yi and Olivier Danvy", > title = "Assessing the Overhead of ML Exceptions by Selective > CPS Transformation", > pages = "103-114", > booktitle = "The Proceedings of the ACM SIGPLAN Workshop on ML", > year = 1998, > url = "http://ropas.kaist.ac.kr/~kwang/paper/98-ml-kiyida.ps.gz", > month = sep > } > > -Kwang > > -- > Kwangkeun Yi http://cs.kaist.ac.kr/~kwang The problem was not to remove try/raise expressions from programs, but to define raise in terms of ``more primitive functions''. I'm not sure a cps transformation can be considered as ``a primitive function'' of the language that can help to define raise into the language. I'm sure you can use a lot of other transformations to remove try/raise, e.g. a monadic transformation or a direct expression of the semantics of exceptions (using a direct sum of normal and exceptional results) could also do the job. Pierre Weis INRIA, Projet Cristal, Pierre.Weis@inria.fr, http://cristal.inria.fr/~weis/ ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2000-08-22 9:31 UTC | newest] Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2000-08-18 2:07 Question on language design (keywords vs Pervasives) Fermin Reig 2000-08-19 16:57 ` Frank Atanassow 2000-08-20 19:01 ` Pierre Weis 2000-08-20 19:55 ` John Prevost 2000-08-21 8:58 ` Pierre Weis 2000-08-21 19:47 ` John Prevost 2000-08-21 21:41 ` Pierre Weis 2000-08-21 16:44 ` John Max Skaller 2000-08-21 21:24 ` Pierre Weis 2000-08-22 0:38 ` Kwangkeun Yi 2000-08-22 2:25 ` John Max Skaller 2000-08-22 9:08 ` Pierre Weis 2000-08-22 8:31 ` Pierre Weis
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox