Fix #554: Document the difference between add, add_global, and set_global (#649)

Updated the cheatsheet to clearly explain that `add` creates thread-local
scoped variables while `add_global`, `add_global_const`, and `set_global`
create global variables shared between all threads. Added a summary table
comparing scope, thread safety, and conflict behavior. Also added a test
exercising the key behavioral differences between these methods.

Co-authored-by: leftibot <leftibot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
leftibot 2026-04-11 11:17:46 -06:00 committed by GitHub
parent 7b45fe19fe
commit fa4b8277f5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 73 additions and 8 deletions

View File

@ -153,17 +153,39 @@ This allows you to pass a ChaiScript function to a function requiring `std::vect
## Adding Objects
```
chai.add(chaiscript::var(somevar), "somevar"); // copied in
chai.add(chaiscript::var(std::ref(somevar)), "somevar"); // by reference, shared between C++ and chai
### `add` — Thread-Local Scoped Variables
`add` adds an object to the current thread's local scope. The variable is only visible in the
thread that added it. If the variable already exists in the current scope, it is overwritten.
```cpp
chai.add(chaiscript::var(somevar), "somevar"); // copied in
chai.add(chaiscript::var(std::ref(somevar)), "somevar"); // by reference, shared between C++ and chai
auto shareddouble = std::make_shared<double>(4.3);
chai.add(chaiscript::var(shareddouble), "shareddouble"); // by shared_ptr, shared between c++ and chai
chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const
chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const, throws if object exists
chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const, throws if object exists
chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object
chai.add(chaiscript::var(shareddouble), "shareddouble"); // by shared_ptr, shared between C++ and chai
chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const
```
### `add_global` / `add_global_const` / `set_global` — Global Shared Variables
Global variables are shared between all threads and are visible from any scope (including inside
functions). Use these when you need a variable accessible everywhere.
```cpp
chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const, throws if value is non-const or object already exists
chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const, throws if object already exists
chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing or creates new
```
### Summary of Differences
| Method | Scope | Thread Safety | If Name Exists |
|--------|-------|---------------|----------------|
| `add` | Thread-local, current scope | Not shared between threads | Overwrites |
| `add_global` | Global, all scopes and threads | Mutex-protected, shared between threads | Throws exception |
| `add_global_const` | Global, all scopes and threads | Mutex-protected, shared between threads | Throws exception |
| `set_global` | Global, all scopes and threads | Mutex-protected, shared between threads | Overwrites |
## Adding Namespaces
Namespaces will not be populated until `import` is called.

View File

@ -0,0 +1,43 @@
// Test demonstrating the difference between add (local scope) and add_global/set_global (global scope)
// See issue #554
// --- Local variables (var / add) are scoped ---
// A local variable defined in a block is not visible outside that block
var local_val = 10
assert_equal(local_val, 10)
// Local variables can be reassigned in scope
local_val = 20
assert_equal(local_val, 20)
// Local variables inside a function are not visible outside
def set_local() {
var func_local = 99
assert_equal(func_local, 99)
}
set_local()
// --- Globals (add_global) are visible everywhere, including inside functions ---
var g_val = 42
add_global(g_val, "my_global")
def check_global() {
assert_equal(my_global, 42)
}
check_global()
// add_global throws if the global already exists
assert_throws("Name already exists in current context my_global", fun() { add_global(1, "my_global") })
// --- set_global overwrites an existing global ---
set_global(100, "my_global")
assert_equal(my_global, 100)
def check_global_updated() {
assert_equal(my_global, 100)
}
check_global_updated()
// set_global can also create a new global if it doesn't exist
set_global(77, "new_global")
assert_equal(new_global, 77)