or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

context-keys-scoping.mdcontext-propagation.mdcore-context.mdexecutor-integration.mdfunction-wrapping.mdimplicit-context-values.mdindex.mdstorage-customization.md

context-keys-scoping.mddocs/

0

# Context Keys and Scoping

1

2

Context keys provide type-safe indexing for values stored in contexts, while scopes manage the lifecycle of context attachments with automatic cleanup.

3

4

## Context Keys

5

6

### Creating Context Keys

7

8

Creates a new context key with an optional debug name.

9

10

```java { .api }

11

static <T> ContextKey<T> named(String name);

12

```

13

14

**Parameters:**

15

- `name` - Debug name for the key (does not affect behavior)

16

17

**Returns:** A new ContextKey instance

18

19

**Usage Example:**

20

```java

21

// Create typed context keys

22

private static final ContextKey<String> USER_ID_KEY = ContextKey.named("userId");

23

private static final ContextKey<Integer> REQUEST_COUNT_KEY = ContextKey.named("requestCount");

24

private static final ContextKey<List<String>> TAGS_KEY = ContextKey.named("tags");

25

26

// Use keys for type-safe storage and retrieval

27

Context context = Context.current()

28

.with(USER_ID_KEY, "user123")

29

.with(REQUEST_COUNT_KEY, 42)

30

.with(TAGS_KEY, Arrays.asList("tag1", "tag2"));

31

32

// Type-safe retrieval

33

String userId = context.get(USER_ID_KEY); // String

34

Integer count = context.get(REQUEST_COUNT_KEY); // Integer

35

List<String> tags = context.get(TAGS_KEY); // List<String>

36

```

37

38

### Key Identity and Comparison

39

40

Context keys are compared by reference equality, not by name. Each call to `named()` creates a distinct key.

41

42

```java

43

// These are different keys, even with same name

44

ContextKey<String> key1 = ContextKey.named("user");

45

ContextKey<String> key2 = ContextKey.named("user");

46

47

Context ctx = Context.current().with(key1, "alice");

48

String value1 = ctx.get(key1); // Returns "alice"

49

String value2 = ctx.get(key2); // Returns null - different key!

50

```

51

52

**Best Practices:**

53

- Store keys as `static final` fields

54

- Use descriptive names for debugging

55

- Create keys once and reuse them

56

57

```java

58

public class UserContext {

59

// Good: single key instance shared across usage

60

private static final ContextKey<String> USER_ID_KEY = ContextKey.named("userId");

61

62

public static Context withUserId(String userId) {

63

return Context.current().with(USER_ID_KEY, userId);

64

}

65

66

public static String getUserId() {

67

return Context.current().get(USER_ID_KEY);

68

}

69

}

70

```

71

72

## Scope Management

73

74

### Scope Interface

75

76

Represents a mounted context that must be closed to restore the previous context.

77

78

```java { .api }

79

interface Scope extends AutoCloseable {

80

static Scope noop();

81

void close();

82

}

83

```

84

85

### No-op Scope

86

87

Returns a scope that does nothing when closed.

88

89

```java { .api }

90

static Scope noop();

91

```

92

93

Used internally when attaching a context that's already current.

94

95

**Usage Example:**

96

```java

97

// Conditional scope creation

98

public Scope attachIfNeeded(Context context) {

99

if (Context.current() != context) {

100

return context.makeCurrent();

101

} else {

102

return Scope.noop(); // No change needed

103

}

104

}

105

```

106

107

### Closing Scopes

108

109

Closes the scope and restores the previous context.

110

111

```java { .api }

112

void close();

113

```

114

115

**Usage with try-with-resources:**

116

```java

117

Context newContext = Context.current().with(USER_KEY, user);

118

119

try (Scope scope = newContext.makeCurrent()) {

120

// Context is active here

121

performOperation();

122

} // Scope automatically closed, previous context restored

123

```

124

125

**Manual closing (not recommended):**

126

```java

127

Context newContext = Context.current().with(USER_KEY, user);

128

Scope scope = newContext.makeCurrent();

129

try {

130

performOperation();

131

} finally {

132

scope.close(); // Must close manually

133

}

134

```

135

136

## Scope Lifecycle Examples

137

138

### Basic Scope Usage

139

140

```java

141

private static final ContextKey<String> OPERATION_KEY = ContextKey.named("operation");

142

143

public void performUserOperation(String userId, String operation) {

144

Context operationContext = Context.current()

145

.with(USER_ID_KEY, userId)

146

.with(OPERATION_KEY, operation);

147

148

try (Scope scope = operationContext.makeCurrent()) {

149

// Context is available to all called methods

150

logOperationStart();

151

executeOperation();

152

logOperationEnd();

153

} // Previous context automatically restored

154

}

155

156

private void logOperationStart() {

157

String userId = Context.current().get(USER_ID_KEY);

158

String operation = Context.current().get(OPERATION_KEY);

159

logger.info("Starting {} for user {}", operation, userId);

160

}

161

```

162

163

### Nested Scopes

164

165

```java

166

public void processRequest(String requestId) {

167

Context requestContext = Context.current().with(REQUEST_ID_KEY, requestId);

168

169

try (Scope requestScope = requestContext.makeCurrent()) {

170

logger.info("Processing request: {}", requestId);

171

172

for (String userId : getUsers()) {

173

Context userContext = Context.current().with(USER_ID_KEY, userId);

174

175

try (Scope userScope = userContext.makeCurrent()) {

176

// Both request ID and user ID available

177

processUser();

178

} // User context ends, request context continues

179

}

180

181

} // Request context ends, original context restored

182

}

183

```

184

185

### Error Handling with Scopes

186

187

Scopes are automatically closed even when exceptions occur:

188

189

```java

190

public void riskyOperation() {

191

Context context = Context.current().with(OPERATION_KEY, "risky");

192

193

try (Scope scope = context.makeCurrent()) {

194

// Context is available

195

performRiskyOperation();

196

197

if (someCondition) {

198

throw new RuntimeException("Operation failed");

199

}

200

201

} // Scope closed even if exception thrown

202

catch (RuntimeException e) {

203

// Previous context is already restored

204

logger.error("Operation failed", e);

205

throw e;

206

}

207

}

208

```

209

210

## Advanced Scope Patterns

211

212

### Conditional Context Application

213

214

```java

215

public void conditionalContext(String userId) {

216

boolean needsUserContext = userId != null && !userId.isEmpty();

217

218

Scope scope = needsUserContext

219

? Context.current().with(USER_ID_KEY, userId).makeCurrent()

220

: Scope.noop();

221

222

try (scope) {

223

performOperation();

224

}

225

}

226

```

227

228

### Scope Delegation

229

230

```java

231

public class ContextualService {

232

private final Service delegate;

233

234

public void serviceMethod(Context context) {

235

try (Scope scope = context.makeCurrent()) {

236

// Service method runs with provided context

237

delegate.performAction();

238

}

239

}

240

}

241

```