For your first question -- there is no single convention for globals in Scheme. Some people use *foo*
(for a reason that is different than the same naming convention in CL, as I said in the above comment), some use CAPITALS (in case-sensitive Schemes), but neither is popular enough to be considered a convention.
The second question is more subtle. Yes, there are pitfalls for having a single global namespace. These pitfalls are the same as the ones in Javascript and as in Common Lisp: it's the fact that loading random code can change the meaning of other code -- so if I want to load two libraries, and both define some foo
global function, then one of these libraries would break the other. This is not a new problem, and there are various ways to deal with it.
The most obvious thing to do is to avoid using globals that are not part of your public interface. So, for example, instead of
(define helper ...)
(define foo ...)
you write
(define foo
(let ()
(define helper ...)
(define foo ...)
foo))
and if you have multiple functions in your interface you do something similar (eg, with Racket's define-values
or using a list of functions). Note that this has a double protection: internal things like helper
don't pollute the global namespace so it won't break other code -- and other code that defines a helper
won't break this code. This includes foo
too, in case it calls itself recursively.
A related hack is to write such code when you want it to be fast: with the first version, a Scheme compiler cannot compile foo
into a fast loop since the binding can be mutated later on, but with the second version such optimizations are possible.
Another form of defensive programming when you don't have a module system is to grab values that are important for your code. For example, you can do this:
(define foo
(let ([+ +] [- -] [* *] [/ /] ... more ...)
(define helper ...)
(define foo ...)
foo))
and now the code has its own immutable bindings to the arithmetic operations, which protects it from changes to these operations in the future and allows safe optimizations of arithmetics in this code.
All of this is kind of a poor man's module-system-by-convention, which is similar to the common use of (function() { ... })()
in Javascript. But of course, a proper module system makes this much more convenient and well behaved. Both newer Javascript versions and newer Scheme versions face this problem with a module system of some sort, and in Scheme the trend is to use only modules and avoid load
as the unreliable hack that it is.
(And since I mentioned Common Lisp: you can see that it has the same problem since you might be overwriting global variables or functions from other files. The way to address that is with CL's package system, which can act as a kind of a weak module system. The reason it's weak is that it gives you the convenience of separate namespaces, but the namespaces are still global which means that optimizations are still very hard. In other words, these namespaces do not give you the "closed world assumption" that conventional module systems have, which means that the compiler still cannot assume that bindings will not change.)