Here are some features like that in Common Lisp, I think. Let me be clear about definitions:

The dynamic extent of (an evaluation of) an expression is the interval of the program’s execution starting when evaluation of the expression begins and ending when control flows out of the expression (ie it returns a value or does some kind of nonlocal transfer of control)

Something is lexically scoped if it may only be referred to by code which is syntactically inside the expression that creates the scope (eg in lisp, a let ordinarily creates a lexical scope but an anonymous function in the body of the let may continue to refer to the lexically scoped binding outside the dynamic extent of the binding; in JavaScript a var binding is in the lexical scope of body of the function in which it is bound)

Something is dynamically scoped if it is available for the dynamic extent of whatever creates the scope.

In Common Lisp most variables are lexically scoped inside the body of the let that defines them. Global variables (or other variables declared special) are dynamically scoped. One can write code like this:

(defvar x 0) ; x is global so dynamically scoped

(defun f (g) (let ((x 1)) (funcall g))

(let ((x 2))
(f (lambda () (print x))))
; => 1
(print x)
; => 0

If x were not defined as a global the output would be 2. If the language had some kind of block scope which was neither dynamic nor lexical, the output would be 0.

This dynamic scope is often used for the kind of “dynamic returns” you describe. There are global variables called e.g. standard-output [written with an asterisk on either side but hn just makes it italic] which one may (dynamically) bind to another stream to capture the output.

Apart from the ordinary control flow out of expressions where they evaluate to something, there are three non local transfer of control constructs:

- catch/throw are a dynamically scoped way of returning values. They work similarly to exceptions in Java or JavaScript except that instead of catch dispatching on the type of the object which is thrown, it dispatches on the identity of a “catch tag” which is associated with whatever value is thrown, and there is no catch-all construct (so it is relatively hard to interfere with someone else’s catch/throw. This is the Common Lisp construct I would refer to as “dynamic return.” These aren’t used very commonly as the below operators tend to be preferred.

- block/return-from is lexically scoped but return-from is only valid within the dynamic extent of the corresponding block. Blocks are named by symbols.

- tagbody/go is much like block/return-from except it is a lexically scoped goto rather than a return. Either could be implemented (potentially less efficiently) in terms of the other.

There is another operator, unwind-protect, which works like a try–finally block in JavaScript to cause some code to run whenever the dynamic extent of an expression ends.

Another example of these scoping concepts is in the condition system which handles errors and other conditions (like warnings or “signals”.) Typically this is implemented using a dynamically scoped variable holding the list of handlers which are currently in scope, and another for the restarts which are just functions. When a condition is signalled, the list of handlers is searched for a suitable handler which is a function that is called. This function has access to the lexical scope from where the handler was defined but runs in the dynamic scope from where the condition was signalled. It may choose to invoke one of the dynamically scoped restarts (proposed solutions to the condition, eg retry or abort) which is just a function that will typically transfer control to some place near to where it was defined. This is different from the traditional exception systems where by the time you catch an exception you’ve already unwound a lot of the stack (so it’s hard to resume from an earlier stage now.)