Logo

dev-resources.site

for different kinds of informations.

if locals == globals

Published at
7/24/2024
Categories
miniscript
programming
beginners
tip
Author
joestrout
Author
9 person written this
joestrout
open
if locals == globals

In MiniScript, as in some other languages, it is common to write a file that's intended to be imported as a module in some larger program β€” but sometimes, to be loaded and run by itself. Typically in the latter case, the point is to demonstrate or unit-test the functionality of that module.

For that to work, your code has to know whether it's being imported, or run in the main program. Today, we're going to see how that's done.

if locals == globals then...

The simple trick is to check whether locals is equal to globals. This is only true for code running in the global scope, that is, in the main program. Import modules run in their own scope, so for them, locals and globals are different.

So a common pattern you'll find at the bottom of many import modules looks like this:

if locals == globals then
   // do some demo or unit test
end if
Enter fullscreen mode Exit fullscreen mode

...run a demo!

A good example of this is /sys/lib/chars, which defines names for all the various special characters in the Mini Micro font. At the bottom of that file, you'll find:

if locals == globals then
    text.clear
    text.row = 25
    print "Special characters:"
    print
    printAlign = function(label, text)
        print " " * (30 - label.len) + label + ": " + text
    end function
    printAlign "left or leftArrow", leftArrow
    printAlign "up or upArrow", upArrow
    // (...etc...)
end if
Enter fullscreen mode Exit fullscreen mode

Screen shot of /sys/lib/chars

...or unit tests!

Many of the other modules in /sys/lib have a runUnitTests function, and the bottom of those generally looks like this:

if globals == locals then runUnitTests
Enter fullscreen mode Exit fullscreen mode

You'll find this in /sys/lib/mathUtil, as well as listUtil, stringUtil, and many others. (Note that we're comparing in the other order here β€” globals == locals rather than locals == globals β€” which makes no difference at all.)

This trick isn't just for general-purpose libraries, either. I used it extensively in making Kip and the Caves of Lava, which consists of over a dozen MiniScript files. Most of these can be run on their own. When run in this way, each module puts its own code through its paces, so I could code/test/debug on just that file, without having to run the whole game.

When is demo also a library?

Occasionally you'll find a program that was intended primarily as a stand-alone demo, to be run and enjoyed on its own, but which can also be imported like a library module. Sometimes this is for historical reasons: something started as a demo, but it was realized that some of its classes and methods might be useful in other apps, so it was made importable.

This is done in exactly the same way as above: all the visible functionality or main program is moved into an if locals == globals block.

Take /sys/demo/cardFlip, for example. This was originally just a stand-alone demo, but in Mini Micro version 1.2, it was refactored to be importable β€” a fact we used recently in making Solitaire. That entailed moving everything besides the CardSprite class into a demo function, and then ending with

if locals == globals then demo
Enter fullscreen mode Exit fullscreen mode

So if you just load and run cardFlip, it behaves exactly as it did before; but now you can also choose to import it (after ensuring that /sys/demo is in your env.importPaths), and use the same CardSprite class in your own code.

Another example is /sys/demo/textAdventure. After defining a bunch of classes and methods for parsing commands, representing rooms, doors, and other objects, etc., the main program starts around line 600:

//----------------------------------------------------------------------
// Main program.
if locals == globals then

    origTextColor = text.color
    origBackColor = text.backColor
    normalColor = color.green
    text.color = normalColor
    text.backColor = color.black
    clear
Enter fullscreen mode Exit fullscreen mode

This code goes on to create the specific text adventure The Greedy Gargoyle, which is what you'll play if you run this program. But if you want to make your own text adventure, you can import this code, and none of that main program stuff runs. You can then make use of all those support classes and functions in your own code.

Screen shot of /sys/demo/textAdventure

No suffocating snakes here

You'll find a similar concept in some other languages. In Python, it's done this way:

if __name__ == '__main__':
Enter fullscreen mode Exit fullscreen mode

But this requires that you remember not one but two magic words, __name__ and __main__, which have little purpose anywhere else. The equivalent MiniScript trick uses no magic words; locals and globals are just the standard, ordinary references to local and global variables, and have many uses besides this trick.

So, the next time you see if locals == globals in some MiniScript file, you'll know what it means. And when writing your own code, I hope you'll remember to consider whether it could be both imported and run on its own β€” and now you know how to make that work.

tip Article's
30 articles in total
Favicon
Ctrl+Alt+Arrow (Right, Left) not working on IntelliJ
Favicon
if locals == globals
Favicon
Version Control Best Practices with Git and GitHub
Favicon
Creating generic types for API (backend) responses
Favicon
Null or Nothing? Unmasking the Mystery of Parameters in Dart
Favicon
List of prompts for successful affiliate marketing
Favicon
My impressions about the book The Clean Coder πŸ§ΉπŸ“š
Favicon
Why You Should Use GraphQL Playground ⏰
Favicon
Automate WEBP To PNG With A Simple .Bat File
Favicon
In CMS Made Simple, how do you change the theme?
Favicon
A importancia de fazer testes
Favicon
Conditional Styles with CSS :has
Favicon
Do you know that 0.1 + 0.2 is not equal to 0.3?
Favicon
How to save datetime data that is relevant to multiple countries or timeΒ zones?
Favicon
What I've Learned About Git from Senior Colleagues (Part 1 - git stash)
Favicon
A (somewhat) deep dive into TypeScript constructor intricacies, step-by-step
Favicon
Faster Color picking in Tailwind
Favicon
Evita usar UpperCase o LowerCase C#
Favicon
#DeveloperTipOfTheWeek - Application Security
Favicon
Running out of space on a developer's machine
Favicon
Alert vs confirm in javascript
Favicon
Quick Tip: Counting up to a limit
Favicon
Quick Tip: findFile
Favicon
Time Saving Tip #2 - User Snippets in VSCode
Favicon
Notify Yourself After Completing a Long-Running Bash Process
Favicon
Time Saving Tip #1 - Use Voice Dictation
Favicon
πŸš€ Unveiling the Power of OpenSearch in 202$: A Comprehensive Overview😎
Favicon
Quick Tip: Checking if a Number is in Range
Favicon
Building a TypeScript Simple Channel (Like Golang)
Favicon
Ubuntu Minimal Install

Featured ones: