Movatterモバイル変換


[0]ホーム

URL:


leafo.net

My projects

View more →

Recent guides

View all →

Recent posts

Dynamic scoping in Lua

PostedJanuary 24, 2016 by leafo (@moonscript) · Tags: lua
Tweet

What is dynamic scoping

Dynamic scoping is a programming language paradigm that you don’t typicallysee. The scoping that most programmers are used to is calledlexicalscoping. It’s found in Lua and many other languages. Lexical scoping is thedominant choice for a reason: it’s easy to reason about and understand just bylooking at the code. We can see what variables are in scope just by looking atthe structure of the text in our editor. Scoping controls how a variable’svalue is resolved.

Dynamic scoping does not care how the code is written, but instead how itexecutes. Each time a new function is executed, a new scope is pushed onto thestack. This scope is typically stored with the function’scall stack. Whena variable is referenced in the function, the scope in each call stack ischecked to see if it provides the value.

An example

Using the syntaxdynamic(var) to represent a dynamic scope variable lookup:

localfunctionmake_printer()locala=100returnfunction()print("Lexical scoping:",a)print("Dynamic scoping:",dynamic(a))endendlocalfunctionrun_func(fn)locala=200fn()endlocalprint_a=make_printer()run_func(print_a)-- prints:-- Lexical scoping: 100-- Dynamic scoping: 200

In this example we're priting a variable nameda with each of the scopingstyles. With lexical scoping it’s very easy to see that we've created a closureon the variablea. That variable is bound to the scope ofprint_a becausethe way the code blocks have been written nest the scopes.

With dynamic scoping things are a bit different. Each entry in the callstackrepresents a different scope to check for the variablea. Because there is noa defined in the function referencing it, we traverse up thecall stack tofind a declared variable. It’s found in the body ofrun_func, where the valueis200.

The usefulness of this scoping may not be immediately clear. It may seem veryerror prone because the value of the variable we're requesting can come fromany caller’s stack, even code that we haven’t event written.

The power of dynamic scoping is that we can inspect the calling context tocontrol the behavior of our functions.

Implementing dynamic scoping

We can implement dynamic scoping fairly easily in Lua through thedebuglibrary. We'll mimic the example above with a function calleddynamic thattakes the name of a variable, as a string, to look up dynamically.

InImplementing setfenv in Lua 5.2, 5.3, and abovewe discovered how we could usedebug.getupvalue to implementsetfenv. For dynamicscoping we'll rely on thedebug.getlocal function.

The signature ofgetlocal isdebug.getlocal ([thread,] level, local). Inthis example we're not concerned with the thread so we'll focus onlevel andlocal.

  • level is an integer that represents how many levels up the call stack we want to look for the variable we're searching for.
  • local is the index of that local variable we want to resolve, starting at 1.

The return value of this function is eithernil if nothing was found, or thename and value of the variable.

To find a local variable in an higher up scope, we just need to keepincrementinglevel and querying each local variable by its numeric indexuntil we find the matching name. Here’s the implementation:

functiondynamic(name)locallevel=2-- iterate overwhiletruedolocali=1-- iterate over each local by indexwhiletruedolocalfound_name,found_val=debug.getlocal(level,i)ifnotfound_namethenbreakendiffound_name==namethenreturnfound_valendi=i+1endlevel=level+1endend

Now we can rewrite the example from the top of the post to use this function:

localfunctionmake_printer()locala=100returnfunction()print("Lexical scoping:",a)-- notice we pass in "a" hereprint("Dynamic scoping:",dynamic("a"))endendlocalfunctionrun_func(fn)locala=200fn()endlocalprint_a=make_printer()run_func(print_a)

When to use dynamic scoping

In the general case, it’s probably best to avoid dynamic scoping since it makescode harder to understand at a glance. In any case, there are some situationswhere dynamic scoping is useful.

DSLs, where terseness is important, canbenefit from dynamic scoping by using the implicit context of function calls tomake arguments available that haven’t been explicitly passed. A basic examplewould be removing the need to passself as an argument if it can be fetchedfrom the containing scope.

Here are some more guides tagged 'lua'
PostedApril 26, 2020
PostedJune 09, 2016
PostedJanuary 28, 2016
PostedAugust 08, 2015
PostedJuly 08, 2015
PostedJuly 08, 2015
PostedJuly 05, 2015
PostedJuly 04, 2015
PostedJuly 04, 2015

leafo.net · Generated Sun Oct 8 13:02:35 2023 bySitegenmastodon.social/@leafo


[8]ページ先頭

©2009-2025 Movatter.jp