This is certainly true, however not everyone uses the phrase “local scope.” Many, it seems, prefer “lexical scope,” which I guess I’m arguing might be a superset of local scope. This specific case (a closure constituted by the enclosed free variables and some disparately implemented methods of a multiply-dispatched function) being the only example I can think of to demonstrate the (symmetric) difference. In symbols:
LEX ⊃ LOC
DISCONTIG ∊ (LEX ∆ LOC)
This excellent blog post goes a bit deeper into the challenges of providing precise definitions for lexical and dynamic scoping. It also references Common Lisp the Language, wherein Guy Steele defines lexical scope as meeting the following property:
references to the established entity can occur only within certain program portions that are lexically (that is, textually) contained within the establishing construct
On the surface, this definition does seem to quash the notion of “discontiguous” lexical scopes, but I’d argue that we could just expand the reading of “the establishing construct” to be a little more broad than regular, old-fashioned, block-local scope. Still very limited in scope, and by no means “global,” however. (I don’t think my first example opens Pandora’s box in terms of breadth of scope: g
’s scope is just another block. Add that block to the block(s) containing the two f
methods, and you have 3 blocks, the union of which constitute the proposed discontiguous lexical scope of f
. Much less than what Steele calls the “indefinite” scope.)
That said, the concern that this becomes less readable is absolutely warranted and should be the foremost criteria in any decision about what constitutes lexical scope. That seems to me to be an entirely subjective determination, but nonetheless one that is unlikely to preclude something approaching consensus. In the manual, we read:
a function’s scope does not inherit from its caller’s scope, but from the scope in which the function was defined
But when is that function defined, exactly? We can see clearly where its methods are, but the whole multiply dispatched function is never really defined as a consolidated entity anywhere! That’s kind of the point of multiple dispatch, as I understand it. (A major language innovation, IMO, totally Turing worthy.) In my earlier version of a MWE, I had the two f
s in two different modules, both import
ing a third, base module, wherein an empty method definition is made. This is actually the pattern I’m going for in my code. I just like doing it that way: sort of like a “bring your own method” style of decentralized programming. But I was sad to lose closures along the way, motivating my post. Anyway, in my understanding, multiple dispatch opens up the possibility of disparate lexical scopes: why else, or previously, would anyone have ever considered such a bizarre (and arguably byzantine) notion?
Not exactly. Yes, to the second half of the question (“the meaning should be different”: to your later point, this is exactly why we use closures), but no to the first half (“f
is called near to a
”). “Nearness” would be entirely subjective, and therefore hard to understand and totally % bonkers. However, in this specific case, g
creates a local scope with a
in it. f
refers to a non-locally-defined a
. Seems like a match made in heaven, but alas, “never in Julia the twain shall meet.” (jk I still love you Julia!) For the first and third examples, this kind of means that a
is “global,” but in this context, “global” just means not local, so we’re caught in something of a logical tautology.
Actually, I’m not really sure that the “global” designation is well defined at all: when a
is captured by f
in the closure of the second original example above, it is not global, but when it fails to be captured in the first example, it is global. So, the compiler’s decision determines whether a
is global? The situation isn’t exactly a tautology, but it does seem like the “tail wagging the dog”: humans tell the compiler how to interpret things, not the other way around. Obviously, if the compiler won’t change, we’re stuck with its designations. But that doesn’t mean we shouldn’t question its assumptions, nor that its interpretation of “global” is the meaning shared by a global audience of programmers. Pedagogically we teach the term, a priori and ab initio, not any one language’s read on it.
As it turns out, in the context of Julia, “global” just means local to the module that the variable is in. So if “local” is taken to mean limited in scope of applicability, and “global” is the least limited in scope, but still happens to be limited in scope as just mentioned, then by the transitive axiom, everything must be local (to something) in Julia.