1

According to the "Section 3 Summary" for Coursera's "Programming Languages, Part A" course (by Dan Grossman of the University of Washington):

But you have seen one feature that is more like dynamic scope than lexical scope: exception handling. When an exception is raised, evaluation has to “look up” which handle expression should be evaluated. This “look up” is done using the dynamic call stack, with no regard for the lexical structure of the program.

I think the writer is talking about Standard ML, but C++ seems also to do the same thing. Do all languages do "exception handling" with such dynamic lookups?

ruakh
  • 175,680
  • 26
  • 273
  • 307
Chen Li
  • 4,824
  • 3
  • 28
  • 55
  • 1
    For information about how C++ specifically handles exceptions, see the awesome answer to [this question](https://stackoverflow.com/questions/307610/how-do-exceptions-work-behind-the-scenes-in-c). This question is too general though, as there's too many languages to make a universal assertion. – hnefatl Oct 11 '17 at 16:02
  • 1
    I’ve never heard of that in SML. Do you have an example that illustrates this, and what you mean by ”dynamic call”? – molbdnilo Oct 11 '17 at 16:07
  • @molbdnilo Page 9 in this document: https://d18ky98rnyall9.cloudfront.net/_34a95c9c790777fb7c103349682d7691_section3sum.pdf?Expires=1507766400&Signature=HnCn7Ps9IclY-nUwNqQ8m7NBGUYsinQ94m7ulj2xgF7K4X4rWVX3vPLLUgoxjsioirS58Q5qPRtSHhvv9kiPXSN6Ox9692N6jYmYVp~VnmKXaWJ4wWaSzxr3piFDfGBKrcPoBUoLzmiao7qPrY4F4WbaGEb0XRGOEytrqVkXnUQ_&Key-Pair-Id=APKAJLTNE6QMUY6HBC5A – Chen Li Oct 11 '17 at 16:13
  • @hnefatl thanks for the link! just driven by curiosity : ) – Chen Li Oct 11 '17 at 16:18
  • @czxyl That's a pretty confused section, and what it describes has nothing to do with what's normally called dynamic scope (locating an exception handler doesn't even involve name lookup). Based on that paragraph, I would recommend that you take that document with a grain of salt. – molbdnilo Oct 11 '17 at 20:39
  • @molbdnilo why "locating an exception handler doesn't even involve name lookup". From the intuitive point of view, I think "name lookup" is correct. – Chen Li Oct 12 '17 at 00:40
  • @czxyl: Your link is broken (expired?). – ruakh Oct 12 '17 at 01:56
  • @ruakh it works fine. I tried just now – Chen Li Oct 12 '17 at 02:20
  • @czxyl: Maybe your browser has cached it, or you have a cookie or something? Because I get `AccessDeniedAccess denied`. – ruakh Oct 12 '17 at 03:09
  • @ruakh you are right : ) try this link: https://d18ky98rnyall9.cloudfront.net/_34a95c9c790777fb7c103349682d7691_section3sum.pdf?Expires=1507939200&Signature=N-8ergFGaeaSvAavs1dyuKdMDeZVDvzaGviup4IiQlzoel-nt5wq4qcoZFEJN0vq9FNxzXgzUBGvZx8e82UTS9yCmHu6ZbkK9-6C55R0rzOpOdwUKPWc~BYjBbSywaNI0g1ggtCVdZ7k7QTiKB-QkXWjNPcEMQVxG7lOcb3GLS8_&Key-Pair-Id=APKAJLTNE6QMUY6HBC5A – Chen Li Oct 12 '17 at 03:24
  • @czxyl: Thanks! I assume that that link will expire soon, too, but I've managed to piece together where you took it from, and have taken the liberty of editing your question to indicate what you're referring to. – ruakh Oct 12 '17 at 04:04
  • @ruakh thanks for your editing! My poor English quite confuses me – Chen Li Oct 12 '17 at 04:08
  • I think it's nigh impossible to say something that would apply to all languages. Especially since I can create my own language that can act as a counterexample. – svick Oct 12 '17 at 12:51

3 Answers3

4

Yes, that is how exception handling works.

FWIW, exception handling as we understand it today was invented in the CLU language in the 70s and developed further in ML in the early 80s. From those it spread into other languages like C++, mostly only with variations on how exceptions are constructed and matched.

It is also worth noting that exception handling is just a special case of a more recently invented generalised mechanism called effect handlers, which is much richer and can express all sorts of other control structure, like coroutines, generators, async/await, even backtracking and more. Its main addition over exception handling is that a handler can resume the throwing computation, passing back a value. Like exception handling all its applications crucially rely on the dynamic extent of handlers.

Andreas Rossberg
  • 34,518
  • 3
  • 61
  • 72
0

(Revised answer)

Do all languages do "exception handling" with such dynamic lookups?

If you define exception handling to always mean: Unwind the call-stack and look for an exception handler, then the resemblance is unavoidable. But there is a difference between "like dynamic scope" and "with dynamic scope".

Incidentally Standard ML allows for locally defined exceptions and does not offer introspection on values, including exceptions. For example, the following program does not type check:

fun foo () =
    let exception Foo
    in bar () handle Foo => true
                   | _   => false
    end
and bar () = raise Foo

It does enforce a control flow that is similar to the identifier lookup mechanism for dynamic scoping, but handlers do not inherit the scope of named exceptions to match against from their parent handler. So I don't think it is reasonable to say that Standard ML exceptions even resemble dynamic scope that much. Common features in dynamic programming languages like exceptions inheriting from a base class and runtime type annotations make the analogy stronger.

There are other error handling systems that pass control flow elsewhere than upwards in the call-stack. For example, you could think of to Erlang's process linking as an exception handling mechanism where multiple linked processes may handle the event of a process exiting. Here, the control flow only vaguely resembles that of dynamic scoping, since there isn't a strict hierarchy, but a graph, of exception handlers. It also isn't very close to any common definition of exceptions, even though a process crashing is exceptional.

sshine
  • 15,635
  • 1
  • 41
  • 66
  • 2
    It turns out that the OP's source is referring to handler lookup: as I'm sure you know, when an exception is raised, the runtime system unwinds the stack to look for a handler, rather than looking for a handler in the lexical scope. (I don't think dynamic scope is a useful way to think of this, but that's what we're working with.) I've edited the question to make this clear. – ruakh Oct 12 '17 at 04:07
  • If you squint a bit and see `raise (Foo a)` as a function call where `raise` is the name of that function, it's pretty clear that the function isn't lexically bound. It's binders are dynamic and are introduced by `handle`, which can be seen as a way of defining the body of the said `raise` function. From this point of view I think exception handling in almost any language looks quite similar to dynamic scope. – Ionuț G. Stan Oct 12 '17 at 13:20
  • What I mean to say is that there is value in this analogy (for some people, at least) and I actually got it before the question was edited. – Ionuț G. Stan Oct 12 '17 at 13:21
  • I see the analogy, but if `raise` is the only function, and the values (like `Foo`) are available in lexical scopes, then even though the control flow of exceptions resembles variable lookups under dynamic scoping, the fact that those values (exceptions) are not inherited from one "function call" (raise) to another, is strikingly unlike dynamic scoping. I only know ML that allows for locally defined exceptions; if exceptions inherited from the same base class, or a "typeof" macro were available, or other introspection existed, it'd be more like dynamic scoping. – sshine Oct 12 '17 at 16:54
  • Right, exception name lookup is lexical. Exception handler lookup is dynamic. – Ionuț G. Stan Oct 12 '17 at 19:18
0

Consider a piece of code like this:

fun add (a, b) = a + b
fun double a = add (a, b)
val _ = double 10

When add returns, it returns control to the next function call on the call stack, namely double. I don't think it's meaningful to think of this as "dynamic scope"; rather, this is just the basic functionality that the call stack provides by virtue of being a call stack.

Similarly, when add raises an exception (such as Overflow), it also returns control to double. (As it happens, of course, double doesn't handle any exceptions, so it implicitly re-raises all exceptions to its own caller.) Dr. Grossman apparently has in mind that a Standard ML implementation would keep a dynamically-locally-scoped record of the innermost handler, so that when you raise an exception, the control jumps directly to a handler instead of passing via double; but that's just an optimization. The behavior is no different than in a Standard ML implementation where the compiled code for double handles propagating exceptions from add.

I think the key point, in both cases, is that add itself cannot "look up" information from its calling context. Rather, add merely exits, restoring control to its calling context.

ruakh
  • 175,680
  • 26
  • 273
  • 307
  • That is one possible view, but the other one is just as valid. In fact, when extending exception handling with resumption you can directly encode dynamic scoping, so the relation is quite close. – Andreas Rossberg Oct 18 '17 at 18:39
  • @AndreasRossberg: When you extend exception handling with resumption, you suddenly have something very different -- just as when you extend `return` with resumption. (No one SFAIK compares e.g. coroutines to dynamic scoping.) – ruakh Oct 18 '17 at 22:15