I will say that for all its faults, RMS's dynamically scoped un-namespaced Emacs Lisp interpreter was far better designed than James Gosling's MLisp interpreter. He honestly copped to how terrible a language MockLisp was in the 1981 Unix Emacs release notes:

https://archive.org/stream/bitsavers_cmuGosling_4195808/Gosl...

12.2. MLisp - Mock Lisp

Unix Emacs contains an interpreter for a language
that in many respects resembles Lisp. The primary
(some would say only) resemblance between Mock Lisp
and any real Lisp is the general syntax of a program,
which many feel is Lisp's weakest point. The
differences include such things as the lack of a
cons function and a rather peculiar method of
passing parameters.

The "rather peculiar method of passing parameters" was an understatement!

When you called a function and passed it parameters that were MLisp expressions, they were not actually evaluated until the CALLED function PULLED the values with the (arg index "prompt") function, at which time the MLisp expressions from the CALLING were evaluated in the dynamic context of the CALLED function!!!

The official convention that we would use at UniPress to develop MLisp libraries that would work together without name clashes was:

Prefix all local variable names with an ampersand, then a (hopefully) unique abbreviation for the function name, then a dash, to make them unique across all known code.

So you could not use the same local variable names between functions that used each others parameters, because expressions passed as parameters would be evaluated with the bindings of the called function!

(I've written a couple of ; comments in the code to explain how it works.)

MLisp has a rather strange (relative to other
languages) parameter passing mechanism. The arg
function, invoked as (arg i prompt) evaluates the
i'th argument of the invoking function of the
invoking function was called interactively or,
if the invoking function was not called
interactively, arg uses the prompt to ask you for
the value. Consider the following function:

(defun
(in-parens ; The name of the function.
(insert-string "(")
(insert-string (arg 1 "String to insert? "))
(insert-string ")")
)
)

If you type ESC-X in-parens to invoke in-parens
interactively then EMACS will ask in the minibuffer
"String to insert? " and then insert the string
typed into the current buffer surrounded by
parenthesis. If in-parens is invoked from an
MLisp function by (in-parens "foo") then the
invocation of arg inside in-parens will evaluate
the expression "foo" and the end result will be
that the string "(foo)" will be inserted into
the buffer.

The function interactive may be used to determine
whether or not the invoking function was called
interactively. Nargs will return the number of
arguments passed to the invoking function.

This parameter passing mechanism may be used to
do some primitive language extension. For example,
if you wanted a statement that executed a statement
n times, you could use the following:

(defun
(dotimes n ; n is not a parameter, it's
; just being "declared" as a local.
(setq n (arg 1)) ; The first argument to dotimes
; is the number of times to do
; the second parameter.
(while (> n 0)
(setq n (- n 1))
(arg 2) ; The second argument to dotimes is
; an expression to evaluate.
; Each time you (arg 2) is called here,
; the caller's second parameter
; expression is evaluated in the
; current context.
)
)
)

Given this, the expression
(dotimes 10 (insert-string "<>"))
will insert the string "<>" 10 times. [Note: The
prompt argument may be omitted if the function can
never be called interactively].

Here's an old Emacs manual with more information about the wonders of MLisp! The Emacs mascot (and icon) was a unicorn, because you needed one of your hands to hold down the control key, and your other hand to hold down the meta key, and a horn on your head to type the letter.

http://bitsavers.informatik.uni-stuttgart.de/pdf/cmu/Gosling...