Ignore this if your language lacks scope. So how do places and time relate to variable scope?
First up is visibility, where you might think of variables as sitting in walled rooms, and so from outside the room (block, or file) the variable is not visible. The variables are somewhere, and if you're not also in that somewhere, the variable cannot be gotten to (well, easily gotten to).
my $x = 42; { my $x = 640; say $x; } say $x;
C is more or less like Perl here, though some compilers may yell at you for shadowing variables in the inner scope.
#includeint main(int argc, char *argv[]) { int x = 42; { int x = 640; printf("%d\n", x); } printf("%d\n", x); }
What C lacks is the "local" variable that Perl has, though in most cases "my" is the sensible thing to use. A local variable is more about when a variable takes on a different value, or maybe will help better distinguish the two.
our $x = 42; { local $x = 640; say $x; } say $x;
Vaguely similar C code to Perl's "local" might look like the following, though Perl jumps through a lot more hoops to ensure that local variables are undone following jumps, exceptions, etc.
int x = 42; { int old_x = x; x = 640; ... x = old_x; }
Aren't these both pretty similar? Sure. In one there's "my" and "my" and the other "our" and then "local", superficially the same. A better example might be a debug flag:
our $DEBUG = 0; ... sub complicated { local $DEBUG = 1; ... warn "foo" if $DEBUG; ... }
To enable debugging but only within the complicated subroutine $DEBUG is localized within that routine. Everywhere else it is off, avoiding debug spam from (hopefully) irrelevant sections of the code. With a lexical variable "my" every block would need a "my $DEBUG = 0" or if $DEBUG was scoped to the whole file then your, uh, "local" debugging would look like
my $DEBUG = 0; ... sub complicated { $DEBUG = 1; ... warn "foo" if $DEBUG; ... $DEBUG = 0; }
which is more tedious (two lines, instead of one) and more error-prone as you have to remember to turn the variable off potentially lots of lines away, and the variable may not be turned off should the code throw an exception or otherwise return early. Some languages have a defer statement to help with this, where something like a "defer { $DEBUG = 0 }" could be put right next to the "$DEBUG = 1" line and guarantees provided that the defer will run come hell or high exception. This may also help those pesky humans who will be less likely to forget about the cleanup code that otherwise lives way over on the yang side of the subroutine.
Actually I'm not sure that the yin and yang sides of a subroutine are, like, which is more sunny?
Also what if $DEBUG could be a range of values?
my $DEBUG = 0; { my $OLD_DEBUG = $DEBUG; $DEBUG = 42; { my $NEW_OLD_DEBUG = $DEBUG; $DEBUG = 640; ... $DEBUG = $NEW_OLD_DEBUG; } $DEBUG = $OLD_DEBUG; }
With "local" this instead is:
our $DEBUG = 0; { local $DEBUG = 42; { local $DEBUG = 640; ... } }
SBCL> (LET ((DEBUG 0)) (LET ((DEBUG 42)) (LET ((DEBUG 640)) (FORMAT T "~&~a" DEBUG)) (FORMAT T "~&~a" DEBUG)) (FORMAT T "~&~a" DEBUG)) 640 42 0
text/gemini
This content has been proxied by September (ba2dc).