Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: extension to catch to only catch certain exceptions #165

Open
jpco opened this issue Jan 10, 2025 · 1 comment
Open

Proposal: extension to catch to only catch certain exceptions #165

jpco opened this issue Jan 10, 2025 · 1 comment

Comments

@jpco
Copy link
Collaborator

jpco commented Jan 10, 2025

Looking at how catch is used, it's quite common to have something similar to

catch @ e type body {
  if {~ $e error} {
    handle-it
  } {
    throw $e $type $body
  }
} {
  commands
}

(error just being an example for illustration). This pattern shows up in the definitions for whatis and while in initial.es as well as the cdpath.es and status.es canonical extension scripts. It would also be required for an es-based definition of $&batchloop which only handles eof. It also appears in the es paper. (It shows up in my .esrc once or twice as well, and in friedman's intense setup a couple of times, for whatever that's worth).

This pattern can add a fair amount of verbosity that doesn't seem strictly necessary. Many languages' exception-handling systems can specify certain types of exception to catch, and something similar could be nice for es, so that the above becomes:

catch error @ {
  handle-it
} {
  commands
}

I am imagining you could also say catch error signal @ {handle-it} {commands} if you want one of a set of exception types. I would probably prefer to spell it catch (error signal) @ {... but that would just be for better legibility; it wouldn't special syntax.

This can be implemented in es today:

fn-catch = $&noreturn @ args {
	if {~ $#args (0 1)} {
		throw error catch 'usage: catch [exceptions] catcher body'
	}
	let (exceptions = ()) {
		$&catch @ {} {
			forever {
				if {~ $#args 2} {throw break}
				exceptions = $exceptions $args(1)
				args = $args(2 ...)
			}
		}
		$&catch @ e rest {
			if {~ $#exceptions 0 || ~ $e $exceptions} {
				$args(1) $e $rest
			} {
				throw $e $rest
			}
		} {
			$args(2)
		}
	}
}

(forever must be used because while works with exceptions, which seems to lead to infinite recursion.) The whole loop could be removed if we could reverse lists like in #82, but that's an aside. This could also all be moved into the $&catch primitive if we wanted that.

@jpco
Copy link
Collaborator Author

jpco commented Jan 28, 2025

Another ergonomic improvement to catch would be if the catcher can be a thunk (if the catcher doesn't care what the exception is). Right now catch {} {throw true} fails because $&noreturn doesn't like to run anything except lambdas. If $&noreturn could run thunks, then catch {} {throw true} would work just fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant