« first day (2721 days earlier)   

7:07 AM
I keep forgetting, but what is a "capsule" in relation to dfns and scoping rules?
(I've asked before, but seem to have not absorbed the idea for some reason.)
 
@B.Wilson As long as you stick to dfns, it doesn't matter for scoping, only stack manipulation. The capsule of a dfn is simply the largest text wherein that dfn is written.
 
Okay. So in the case of a stack with mixed tradfns and dfns, would the capsule refer to the scope of the most recently-called tradfn?
Not sure I see what you're driving at with "stack manipulation".
 
@B.Wilson No, again, a capsule has nothing to do with scoping, only stack manipulation. If you have mixed tradfns and dfns, then I believe any given dfn's capsule is the outermost dfn wherein the dfn in question is contained.
Stack manipulation includes "cutting to the capsule" on the top of the stack, and signalling out of the capsule.
 
7:32 AM
Okay. I'm mainly wondering how the concept interacts with ⎕SHADOW and Execute, and uh, one-line dfns.
Maybe it doesn't at all. I am just seeing discussions of capsule pope up in discussions of scope here and there.
More clearly, perhaps. I'm wanting to get a crisp understanding of the (funky) scoping behavior of Dyalog. So far, I know relevant concepts to consider include, tradfns, multi-line dfns, one-line dfns, Execute, and ⎕SHADOW. But I'm wondering if I need to worry about any other ontological categories as well, like capsule.
 
@B.Wilson OK, so there's no difference between multi-line and one-line dfns when it comes to scope. The only difference between them is that you cannot suspend in a one-liner. The things you mention uses dynamic scoping, except for dfn-to-dfn calls which are lexical, and execute sees what its context sees. ⎕SHADOW only applies to tradfns and should be fairly straight-forward. Error guards are dynamic and introduce a scope which we roll back to when triggered. I think that's all.
@user25732704 Hi Jeneliza Magnetico, if you want to participate here, please email [email protected]
 
7:53 AM
@Adám Execute definitely escapes lexical boundaries: a←'I am overwritten'⋄f←{⍎'a←1'}⋄f⍬
 
@B.Wilson Nothing to do with as a←'I am overwritten'⋄f←{a⊢←1}⋄f⍬ does the same.
Which makes sense. That a is in the lexical scope of f.
      a←0 ⋄ g←{a←1 ⋄ f⍬} ⋄ f←{⎕←a} ⋄ g⍬
0
↑ shows that f uses lexical scope. It cannot see g's a because it wasn't defined inside g in contrast with:
      a←0 ⋄ g←{a←1 ⋄ f←{⎕←a} ⋄ f⍬} ⋄ g⍬
1
 
Remove the outer scope definition of a. You'll notice that ⍎'a←1' acts more like a∘←1 than modified assignment.
 
Yes, of course, but that's immaterial. Modified assignment just requires the variable to already be defined.
a∘← is just exploiting a bug such that the dfn processor fails to localise the name.
You can write ⎕THIS.a← instead to avoid localisation and not use a hack.
Clearly, ⎕THIS refers to the current namespace as seen inside the dfn, but it can still see the global.
 
Seems pretty material to me. ⍎'a←1' within a lexical boundary introduces or modifies variables outside of said boundary. I'm not sure why comparing with modified assignment is natural at all.
 
But it doesn't go outside its lexical boundary. Any function can see "up". Question is whether "up" refers to the stack or the definition.
if "up" refers to the stack then you have dynamic scope
if "up" refers to the definition then you have lexical scope
It is when you mix trad and d that things get "interesting" (i.e. dynamic scope prevails):
      ∇ (f _ScopeBreaker)y
[1]     f y
[2]   ∇
      a←0 ⋄ g←{a←1 ⋄ f _ScopeBreaker⍬} ⋄ f←{⎕←a} ⋄ g⍬
1
If we use a dop, then the whole stack is written in d, and so lexical scope prevails:
      _ScopeKeeper←{⍺⍺ ⍵}
      a←0 ⋄ g←{a←1 ⋄ f _ScopeKeeper⍬} ⋄ f←{⎕←a} ⋄ g⍬
0
 
8:09 AM
For finding values of names, that's sufficient explanation perhaps, but we're talking about where and how to assign a (potentially new) name. In this case, Execute definitely doesn't do the same thing as "its context".
 
I didn't say that execute would "do" either. I said that (my emphasis): "execute sees what its context sees"
That is, the scope is the same. There are other differences beween execute and its context. For instance, execute handles multi-line strings and allows control structures in dfns!
 
Oh, I think you're using "scope" to mean the particular scoping behavior, i.e. dynamic vs. lexical and "context" to mean what I mean by "scope".
Maybe "scoping context" would be maximally unambiguous in this particular case.
 
Ah, that makes sense. Sorry.
 
No worries :) So it seems like Execute only introduces new names at the scoping context corresponding to the enclosing capsule?
(I could swear I had an example where single- and multi-line dfns differed in the particular scoping context they touched.)
 
@B.Wilson While I'm not entirely sure what your words mean, it doesn't strike me as correct:
      ∇foo;bar
[1]    bar←{⍎'a←1'}
[2]    bar⍬
[3]   ∇
      foo
      a
1
Would call foo the enclosing capsule of bar? If so, then we have execute introduce a new name outside its capsule?
 
8:28 AM
Well, if we localize a in foo, then it doesn't propagate.
I'm probably just not getting what you mean by capsule, but in this case, I'm thinking of whatever scope context is introduced by foo.
 
But then arguably, execute didn't create the name in the symbol table; it just populated it with a value. Similar to how you can have an unpopulated field in a class:
      (⎕FIX':class' ':field public shared a' ':endclass').⎕nl¯2
 a
      (⎕FIX':class' ':field public shared a' ':endclass').a
VALUE ERROR
      (⎕FIX':class' ':field public shared a' ':endclass').a
      ∧
@B.Wilson OK, I'm using the name "capsule" as I defined above regarding stack manipulation of dfns. But yes, this confirms what I said above that execute sees the same as the code that called it. If foo would shadow a then just as bar cannot see any a outside foo because foo shadows a, so too inside bar cannot see (use, create…) any a outside foo because foo shadows a.
 
Exactly. It's like there are slightly separate mechanisms that define the lexical (context) boundaries between variable references and variable assignments. In the case of a←1 we assign to one context but in ⍎'a←1' we assign to the other.
 
Oh, sorry for the confusion. The glyph is overloaded. It means two very distinct things directly in dfns (not inside in dfns) vs everywhere else. Should have been two different glyphs imo.
name←value in a dfn is essentially equivalent to name←value⊣⎕SHADOW'name' outside dfns.
(things get a bit hairy when you have multiple names, but the idea is the same; shadow every name to the left of before assigning)
(and this is only for "normal" assignments, not for namespace assignments like ns.name← and not for modified assignments like name+←, and not for hacky assignments like name∘←)
 
Okay. So ⎕SHADOW effectively is just an explicit way to introduce a lexical boundary that begins at the call site and ends at the enclosing tradfn or dfn?
 
tradfn only, as I said before, "⎕SHADOW only applies to tradfns"
A very unfortunate effect of the above "everywhere", is that it includes the interactive session. So you might be suspended in a dfn during development, then experiment in the session until you perfect your expression. Then you copy it into your dfn and continue execution, only for your perfected expression to mean something entirely different.
 
8:41 AM
Oh. Oh. Fun.
Namespace (plain) assignment just always does the expected thing, right?
 
Yes, that's just normal assignment everywhere.
And same with modified assignment.
 
Perfect.
(Also, you can pull excalibur from my cold, dead hands :P)
 
name∘← accidentally derives a monadic function where the left operand is a symbol (as in a symbol table, not a glyph) though Dyalog does its best to avoid exposing symbols.
@B.Wilson You might think that "shadow or not shadow" is a minor difference, but it is actually huge, because APL prohibits overwriting (but not shadowing) nameclasses 2 and 9 with nameclasses 3 and 4, and Dyalog allows multiple assignment without parens, so this is necessary to infer if you're doing multiple assignment, modified assignment, or using the passthrough value from an assignment.
 
Huh. So some multiple assignment can turn into a passthrough and execution if shadowing changes nameclasses in the right way?
 
I don't think that can happen. Only the converse that passthrough and modified can turn into multiple:
      Minus←-
      ∇foo;a
[1]    a←10
[2]    Minus←1
[3]  ∇
      foo
9
      fooD←{
        a←10
        Minus a←1
      fooD⍬
1
      ∇boo;a
[1]    a←10
[2]    ⎕←Minus a←1
[3]   ∇
      boo
¯1
      booD←{
        a←10
        ⎕←Minus a←1
      }
      booD⍬
1
We can get the D effect by appending ⊣⎕SHADOW'a' 'Minus' to line [2] in the tradfns.
 
8:57 AM
@Adám Comparing foo and fooD, should foo[2] be a Minus ←1 ?
 
No, that's totally messed up. First block should be (hope I get it right now):
      Minus←-
      ∇foo;a
[1]    a←10
[2]    a Minus←1
[3]  ∇
      foo
9
      fooD←{
        a←10
        a Minus←1
      fooD⍬
1
 

« first day (2721 days earlier)