Skip to content

Commit d80922c

Browse files
committed
add new doc for local scope
1 parent 262175e commit d80922c

File tree

2 files changed

+216
-0
lines changed

2 files changed

+216
-0
lines changed

docs/recipes/environment-variables-system-properties.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ To change this behavior, you can set the environment variable `LUCEE_ADMIN_MODE=
132132
**System Property:** `-Dlucee.admin.mode.default`
133133
This setting functions similarly to `LUCEE_ADMIN_MODE`, but it only affects the default behavior and can be overridden by any setting in `.CFConfig.json`.
134134

135+
**Environment Variable:** `LUCEE_CASCADING_WRITE_TO_VARIABLES_LOG`
136+
**System Property:** `-Dlucee.cascading.write.to.variables.log`
137+
This setting only applies to Lucee 6 (above `6.2.1.82`). Enables logging when variables are implicitly written to the variables scope (without an explicit scope definition). When set to a log level name (e.g., "application"), Lucee will log details about variables being assigned without explicit scope at the DEBUG level. This helps identify code that could be optimized by using proper variable scoping.
138+
135139
## Breaking Changes
136140

137141
Major updates for Lucee can sometimes cause breaking changes. The settings below allow you to emulate the behavior of older Lucee versions in newer versions.
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
<!--
2+
{
3+
"title": "Migrating from Classic to Modern Local Scope Mode",
4+
"id": "local-scope-migration",
5+
"categories": ["scopes", "variables", "migration"],
6+
"description": "Guide for safely migrating your Lucee application from classic to modern local scope mode",
7+
"keywords": [
8+
"local scope",
9+
"variables",
10+
"migration",
11+
"scope mode",
12+
"classic mode",
13+
"modern mode"
14+
]
15+
}
16+
-->
17+
18+
# Migrating from Classic to Modern Local Scope Mode
19+
20+
Lucee offers two different modes for managing unscoped variables within functions: Classic and Modern. This document explains the differences between these modes and provides a structured approach for migrating from Classic to Modern mode.
21+
22+
## Understanding Local Scope Modes
23+
24+
The "Local scope mode" setting defines how variables with no explicit scope are handled within functions:
25+
26+
* **Classic Mode (CFML Default)**: Unscoped variables are stored in the variables scope, unless the key already exists in one of the function's local scopes (arguments or local).
27+
* **Modern Mode**: Unscoped variables are always stored in the local scope, regardless of whether they exist elsewhere.
28+
29+
## Why Migrate to Modern Mode?
30+
31+
Modern mode offers several advantages:
32+
33+
1. **Thread Safety**: Variables are isolated to the function instance, preventing race conditions when component instances are shared across requests.
34+
2. **Predictable Behavior**: All unscoped variables behave the same way, making code more intuitive and easier to maintain.
35+
3. **Performance**: Local scope lookups are typically faster than cascading scope resolution.
36+
37+
### Classic Mode Race Condition Example
38+
39+
Consider this component when running in Classic mode:
40+
41+
```javascript
42+
component {
43+
function createToken(id) {
44+
token = createUUID(); // Stored in variables scope
45+
storeToken(id, token);
46+
return token;
47+
}
48+
}
49+
```
50+
51+
If this component is stored in application scope and used across multiple concurrent requests, `token` becomes a shared variable. This creates a race condition where multiple threads could overwrite each other's values.
52+
53+
## Configuring Local Scope Mode
54+
55+
Local scope mode can be configured at several levels:
56+
57+
### 1. Server Level (Lucee Administrator)
58+
Under "Settings > Scope", set "Local scope mode" to either "Modern" or "Classic".
59+
60+
### 2. Server Configuration (.CFConfig.json)
61+
```json
62+
{
63+
"localScopeMode": "modern"
64+
}
65+
```
66+
Or:
67+
```json
68+
{
69+
"localScopeMode": "classic"
70+
}
71+
```
72+
73+
### 3. Application Level (Application.cfc)
74+
```javascript
75+
this.localMode = "modern"; // or "classic"
76+
```
77+
78+
### 4. Function Level
79+
```javascript
80+
function test() localMode="modern" {
81+
// Function body
82+
}
83+
```
84+
85+
## Migration Strategy: Using Cascading Write Logging
86+
87+
Switching directly to Modern mode may break existing applications that rely on Classic behavior. A safer approach is to:
88+
89+
1. Enable variable scope cascading write logging
90+
2. Identify and fix all occurrences of unscoped variables
91+
3. Switch to Modern mode
92+
93+
### Step 1: Enable Cascading Write Logging
94+
95+
Set the following environment variable or system property (This setting only applies to Lucee 6.2.1.82 and above):
96+
97+
**Environment Variable:** `LUCEE_CASCADING_WRITE_TO_VARIABLES_LOG`
98+
**System Property:** `-Dlucee.cascading.write.to.variables.log`
99+
100+
Example:
101+
```
102+
# Environment variable
103+
LUCEE_CASCADING_WRITE_TO_VARIABLES_LOG=application
104+
105+
# System property
106+
-Dlucee.cascading.write.to.variables.log=application
107+
```
108+
109+
This will log all instances where variables are implicitly written to the variables scope.
110+
111+
### Step 2: Analyze Logs and Modify Code
112+
113+
Monitor your application logs for entries like:
114+
115+
```
116+
Variable Scope Cascading Write Detected: The variable [token] is being implicitly written to the variables scope at [MyComponent.cfc:42]. This occurs when no explicit scope (such as local, arguments, or variables) is specified in the assignment.
117+
```
118+
119+
For each occurrence, decide whether to:
120+
121+
1. **Add explicit variables scope** (if the variable should remain in the component's variables scope):
122+
```javascript
123+
variables.token = createUUID();
124+
```
125+
126+
2. **Add explicit local scope** (if the variable should be function-local):
127+
```javascript
128+
local.token = createUUID();
129+
```
130+
131+
### Common Patterns Requiring Attention
132+
133+
#### Component Properties
134+
135+
Properties meant to be stored at the component level need an explicit variables scope:
136+
137+
```javascript
138+
// Before
139+
function init(datasourceName) {
140+
datasourceName = arguments.datasourceName;
141+
}
142+
143+
// After
144+
function init(datasourceName) {
145+
variables.datasourceName = arguments.datasourceName;
146+
}
147+
```
148+
149+
#### Local Counters and Temporary Variables
150+
151+
Variables that should be local to a function call:
152+
153+
```javascript
154+
// Before
155+
function processItems(items) {
156+
result = [];
157+
for(i=1; i <= arrayLen(items); i++) {
158+
processed = processItem(items[i]);
159+
arrayAppend(result, processed);
160+
}
161+
return result;
162+
}
163+
164+
// After
165+
function processItems(items) {
166+
local.result = [];
167+
for(local.i=1; i <= arrayLen(items); i++) {
168+
local.processed = processItem(items[local.i]);
169+
arrayAppend(result, processed);
170+
}
171+
return result;
172+
}
173+
// or simply set local mode explicitly
174+
function processItems(items) localMode=true {
175+
result = [];
176+
for(i=1; i <= arrayLen(items); i++) {
177+
processed = processItem(items[i]);
178+
arrayAppend(result, processed);
179+
}
180+
return result;
181+
}
182+
```
183+
184+
185+
### Step 3: Test Thoroughly
186+
187+
After updating your code:
188+
189+
1. Test your application thoroughly
190+
2. Verify that all functionality works correctly
191+
3. Look for unexpected behaviors or errors
192+
4. Make sure you no longer get any log entries
193+
194+
### Step 4: Disable Logging and Switch to Modern Mode
195+
196+
Once all code has been updated and tested:
197+
198+
1. Disable the cascading write logging by removing the environment variable or system property:
199+
```
200+
# Remove environment variable
201+
unset LUCEE_CASCADING_WRITE_TO_VARIABLES_LOG
202+
203+
# Or remove system property from startup configuration
204+
# -Dlucee.cascading.write.to.variables.log
205+
```
206+
207+
2. Switch to Modern mode at your preferred configuration level (server, application, or function).
208+
209+
210+
## Conclusion
211+
212+
Migrating to Modern mode improves thread safety and code predictability, but requires careful examination of existing code. Using cascading write logging helps identify potential issues before they become problems, allowing for a smooth transition.

0 commit comments

Comments
 (0)