Subject: Re: About the usage of throw/catch
From: Erik Naggum <erik@naggum.no>
Date: 2000/02/14
Newsgroups: comp.lang.lisp
Message-ID: <3159477157011411@naggum.no>

* arolambler@aol.com (ArolAmbler)
| I phrased it in a way subject to misintrepretation.  Since the dynamic
| scope of a tag ends with the dynamic scope of the tagbody, it is not
| legal tn CL to create closures over recursive tagbodies, and go to tags
| for tagbodies that have been exited.  (Although I strongly suspect some
| implementations do not detect the problem, and some may even support it
| properly.).

  well, I asked for an example, got it, and now I'm asking for more.  why
  this "strongly suspect" point?  it seems you're creating problems for the
  purpose of creating or showing off complexity, not for the opposing, much
  more reasonable, purpose of solving them and reducing overall complexity.
  (this is a more verbose version of the "ivory tower" accusation.)

| Thus, foo is called recursively, so there are multiple closures and
| tagbodies active.

  a GO is explicitly defined to reach the innermost accessible tag, so this
  is not a semantic problem.  it may be a pragmatic or stylistic problem in
  that you can't easily figure out which tag is the innermost, however.

| As to "throw/catch" being "needed".  That is true, WHEN you have to glue
| together stuff in a hurry, and can't change the interfaces to some of it.

  I think you should consider the possibility that you have overlooked
  something when you make sweeping generalizations like this.  it is quite
  annoying to have to deal with statements that are true but incomplete,
  yet false when completed or extended to their natural context.  that is,
  your assessment of the situation is relevant, yet not the only one that
  needs to be considered, and therefore, the conclusion does not hold for
  anyone but those who restrict themselves to your particular context.
  again, "ivory tower" might apply to such strong yet narrow arguments.

| BUT: it is far better to make the result value have one or more
| "exceptional" values (such as null in ANSII SQL, or the NANs of IEEE
| floating point arithmetic).  The operations all "propagate" the
| exceptional VALUE, without any non-local control transfer.

  I was disappointed when waiting for the capitalized WHEN to support the
  "it is far better" sweeping generalization sans reservations or context.
  in some contexts, what you propose is indeed a good idea.  few people use
  CATCH/THROW or other exception-handling mechanisms in such contexts, for
  the very simple reason that the first time they run into a problem, they
  will most probably swear and even more probably redesign their code.  in
  the context of an exception-handling mechanism that is ill-designed, we
  do have the option of talking to the people who wrote the code and even
  in many cases to do what you consider so gross -- to wrap up the code in
  some advice or whatever to protect you from harm, but doing so in cases
  where it clearly has no value is an argument against your generalization.

| As I said in the first post on this issue: non-local transfer of control
| is dirty, because it does not "reuse" well.

  yes, this is so, in _some_ contexts, but I'm getting increasingly curious
  why you exclude all _other_ contexts as inherently irrelevant to any
  discussion of this language feature or of exception-handling in general.

| Said in a more sophisticated way, incomprehensible probably to the
| original poster, neither functors nor combinators in general, nor any
| function that maps a function over a set of values can easily use any
| function that sometimes throws, unless the function is first "cleaned up"
| by wrapping a catch, return exceptional value piece around it.  And
| repetitively "cleaning up" every time I reuse a function means the
| function has a bad behavior.

  this is obviously a bogus general claim.  most of the time, we are not
  faced with irreversible side effects of our functions, and we are not
  therefore in need of a transactional approach to "committing" or not
  "committing" whole executions of complex pieces of code.  it helps, and
  I'll easily grand you that, to know _when_ to require a simple "completed
  or not done at all" result from a function, however.

  "best effort"-functions that return some "impossible" values may actually
  have the annoying consequence that the failure mode is _less_ predictable
  than an exception, as _some_ transactions were "committed" after some
  failure had occurred, meaning that the failed transactions now have to be
  committed out of order, or not at all, which is very different from an
  _aggregate_ "commit".  I hope you appreciate this distinction.

  I'm not interested in your ad hominem arguments: just because you have
  shipped so-and-so-products does not lend any credibility to any of your
  arguments -- I'm _not_ interested in who you are or what you have done; I
  _am_ interested in whether you can support your sweeping arguments
  without reference to such claim to fame or credentials, the inclusion of
  which in my view detracts very significantly from effective argumentation.

#:Erik, who's beginning to discover that vacations have serious down-sides :)