I never thought I’d see the day that dynamic scope was mentioned as a reason for using a language.
I’m pretty sure I understand scope well and I consider myself a dynamic scope survivor due to my use of emacs lisp. I’ve never liked it though. So, for those of us who don’t remember Perl 4, what is dynamic scope?
You know those "global" variables that perl provides, such as $/ ? When you do this:
{
local $/ = undef;
# code
}
you’re introducing a dynamic scope. $/ is set to its previous value after the scope finishes.
Emacs Lisp and Dynamic Scope
Emacs lisp has loads of global variables all over the place that you can override. One I use a lot is inhibit-read-only. Dynamically scope that to non-nil and it is possible to write into read-only buffers.
(let ((inhibit-read-only t))
(insert "hello"))
Back to Perl.
Under the covers, the <> operator is probably implemented a bit like this (only much more efficiently).
open my $fh, '<', $ARGV[0];
printf '^^^%s$$$' . "\n", get_input($fh);
{
local $GLOBAL::delimiter = undef;
printf '^^^%s$$$' . "\n", get_input($fh);
}
sub get_input
{
my $fh = shift;
my $buffer = '';
my $c;
while (!defined($GLOBAL::delimiter) or $buffer !~ /$GLOBAL::delimiter$/) {
my $read = read $fh, $c, 1;
if (!defined($read)) {
die $!;
} elsif (!$read) {
last;
}
# printf "C is[%s]\n", (ord($c) < 32) ? ord($c) : $c;
$buffer .= $c;
}
return $buffer;
}
If you’re not a dynamic scope aficionado, you’re probably thinking, why doesn’t get_input just have another parameter called delimiter which is defaulted to "\n" or whatever.
The dynamic scope guys will probably respond that what about if you need to override the behaviour from the top of a deep deep call stack ?
I have a bunch of superior ways of doing this using O-O and dynamic scope doesn’t play nicely with my [mostly] lexical variables in any case.
And Finally…
I was under the impression that dynamic scope was pretty much non-existent in modern languages. Perl and Common Lisp have it, but lexical scope is, at least culturally, the default. Python doesn’t really have proper scoping at all. Dunno about Ruby, did those guys inherit it?
I was surprised to see Stevan mention in the comments that F# has it.