Lexical Scope

145 views
Skip to first unread message

STeEL

unread,
Jan 24, 2021, 11:24:59 AM1/24/21
to Blockly
Hallo,

I'm working on a project to design static type pl (with feature of functional and oo) using blockly. I confuse how to access all block in statement input and how to get parent block instance :( . I need to add lexical scoping feature in my language. The concept is similar to tree which is i can get info of my current leaf and info of parent nodes.

Thanks

Beka Westberg

unread,
Jan 24, 2021, 5:48:57 PM1/24/21
to blo...@googlegroups.com
Hello!

That sounds like a super cool project :D I love it when people want to do new type-checking stuff with Blockly!

One thing you might want to look into is AppInventor, since they provide local lexically-scoped variables using custom blocks :D The block definitions are here and most of the logic is here. The logic is a bit messy, but it handles variable renaming and capture really thoroughly! So I think it's a good resource :D

As for your specific question about accessing the child blocks of a statement input, you should:
1) Call getInputTargetBlock on the block you want to get the children of, passing the name of the specific statement input. This gets you the block that is *directly* connected.
2) Call either getChildren or getDescendants on the returned block to get the rest of the blocks in the statement input. Check the documentation on those because they work slightly differently, and I'm not exactly sure which you want =)

As for your specific question about getting the parent block, you should use getParent, getSurroundParent, or getRootBlock depending on what exactly you're looking for =)

One last thing, if you're interested in typing you might be interested in my design document that talks about creating a plugin for a more advanced nominal type system. It doesn't deal with scoping, but I thought you might be interested nonetheless. Any comments/suggestions are very much appreciated :D

I hope that helps! If you have any further questions please reply!
--Beka



--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/blockly/db130237-a29a-4965-9b77-fea4e5cf58e2n%40googlegroups.com.

Coda Highland

unread,
Jan 24, 2021, 5:50:25 PM1/24/21
to blo...@googlegroups.com
Lexical scope is hard. Even function scope is hard, but function scope CAN be done with the right level of fiddling, and if you can compromise on using function scope instead of lexical scope then you can introduce a distinction between local variables and global variables, and then you can have the blocks that define functions scan through their children to see what variables need to be declared at the top of the function.

/s/ Adam

--

Beka Westberg

unread,
Jan 24, 2021, 6:20:32 PM1/24/21
to blo...@googlegroups.com
Sorry to hijack the thread, but what makes lexical function-scope easier than generalized lexical scoping? 

I guess I'm a bit confused about what you mean by function scope vs generalized lexical scoping. Does it just mean that in your implementation, function parameters aren't declared as globals, but everything else is? Or is it something subtler?

Sorry if you've told me this before haha I can't remember what we've discussed about your custom function implementation and what we haven't. I'm really curious about how you decided to implement this!

Cheers,
--Beka

Coda Highland

unread,
Jan 24, 2021, 6:50:31 PM1/24/21
to blo...@googlegroups.com
True lexical scoping means that

int foo() {
    int a = 3;
    { int a = 2; }
    return a;
}

declares two different variables named a, and foo() returns 3.

Javascript notably did not have lexical scoping when it was invented. Until the introduction of `const` and `let`, it only had function scoping -- any variable declared with the `var` keyword within a function is scoped to the entire function, even if you were to declare it within a smaller code block.

Yes, you could implement generalized lexical scoping in Blockly, if you REALLY wanted to. The issue that arises is that you would then have to have blocks for declaring variables, and users would be responsible for explicitly making use of them. This rather defeats the point of Blockly, if you ask me -- sure, you could use Blockly as just a visual overlay that maps token-for-token onto the target language's code, but at that point there's really not a whole lot of reason not to just use text. Blockly shines brightest when the user can focus on logic and ideas instead of having to worry about syntax. It's explicitly a design philosophy that Blockly shouldn't have a notion of syntax errors.

Function scoping is much simpler. You only have two scopes to worry about: local and global. In an environment such as Blockly, this means that one possible implementation would be to have one type of block for local variables, and one type of block for global variables.

This is SORT OF like Blockly's handling of function parameters. Function parameters get put in the pool of global variables, but then they get treated like function-scoped local variables when you use them at run time. I do think for Blockly's primary target use case that this is the right decision: while it's possible that this behavior could be a little confusing to novices defining functions for the first time, it's a simple enough concept to get an intuition for. It's less cognitive overhead than trying to learn about two different kinds of variables. But it's not good enough for programs with recursive functions -- for non-recursive functions you can just use different "global" variable names to store local values that shouldn't get stomped on, but for recursive functions there's simply no way to make that work without proper local variables.

/s/ Adam

Coda Highland

unread,
Jan 24, 2021, 6:54:03 PM1/24/21
to blo...@googlegroups.com
As an aside: For the record, I HAVEN'T implemented this in mine. I actually have three scopes, not two, because my engine is object-oriented. This provides enough namespace isolation that this problem never came up for me -- I hadn't ever thought about the problem with recursive functions! So my only function-scoped variables are function parameters. I should probably fix this. :P

/s/ Adam

STeEL

unread,
Jan 26, 2021, 7:51:23 AM1/26/21
to Blockly
Hi, 

Thank you for the response (I will try all your suggestions) and also for the static type documentation (proposal). custom blocks (AppInventor), yes it is almost same with what i meant. I red the proposal for subtyping and variance, it is cool but our design is different. 
~STeEL

STeEL

unread,
Jan 26, 2021, 7:57:44 AM1/26/21
to Blockly
Hi,

Good explanation, how about shadowing?
~STeEL

Coda Highland

unread,
Jan 26, 2021, 11:06:07 AM1/26/21
to blo...@googlegroups.com
Hmm... That brings a good point.

Shadowing is just a natural effect of scoping rules. In textual programming languages, if you want to avoid shadowing, you just make sure to use a different variable name. Some languages have a way to explicitly reach out into a broader scope, such as PHP's $GLOBALS, Lua's _ENV, or Javascript's window object, but not all languages do.

If you were to use a separate set of Blockly blocks for local variables, then you could refer to both local and global variables of the same name in the same function. This means that shadowing wouldn't be a problem in Blockly, but it could potentially mean that you could get into a situation where you can't generate legal code in the target language.

Fortunately, the solution is easy: just don't allow the variables to have colliding names! You could, for example, put a prefix on the names of local variables in the generated code.

/s/ Adam

STeEL

unread,
Jan 26, 2021, 3:19:49 PM1/26/21
to Blockly
Thank you Adam, I add shadowing  in my language :) .
Reply all
Reply to author
Forward
0 new messages