0
# Control Flow and Utilities
1
2
Boundary-based control flow, utility types, and helper functions including structured exception-like control flow and advanced utility classes.
3
4
## Capabilities
5
6
### Boundary Control Flow
7
8
Structured control flow using boundary/break pattern for non-local returns.
9
10
```scala { .api }
11
/**
12
* Boundary control flow system providing structured "break" functionality
13
*/
14
object boundary:
15
/**
16
* Create a boundary with a label, enabling break operations within the block
17
*/
18
def apply[T](body: Label[T] ?=> T): T
19
20
/**
21
* Break from the nearest enclosing boundary with a value
22
*/
23
def break[T](value: T)(using Label[T]): Nothing
24
25
/**
26
* Break from the nearest enclosing boundary without a value (Unit)
27
*/
28
def break()(using Label[Unit]): Nothing
29
30
/**
31
* Label type for boundary operations
32
* Represents a typed break target within a boundary
33
*/
34
sealed abstract class Label[-T]
35
36
/**
37
* Exception type used internally for break operations
38
*/
39
final class Break[T](val value: T) extends Throwable with scala.util.control.ControlThrowable
40
```
41
42
**Usage Examples:**
43
44
```scala
45
import scala.util.boundary
46
import scala.util.boundary.break
47
48
// Basic boundary usage
49
val result = boundary {
50
for i <- 1 to 100 do
51
if i > 50 then break(i)
52
println(i)
53
-1 // Default value if no break
54
}
55
println(result) // 51
56
57
// Boundary with Unit return type
58
boundary {
59
val items = List(1, 2, 3, 4, 5)
60
for item <- items do
61
if item == 3 then break()
62
println(s"Processing $item")
63
}
64
65
// Nested boundaries with different types
66
val nested = boundary[String] {
67
boundary[Int] {
68
if someCondition then break(42)
69
if otherCondition then break("early exit") // Breaks outer boundary
70
100
71
}.toString
72
}
73
74
// Early return from function
75
def findFirst[T](items: List[T])(predicate: T => Boolean): Option[T] =
76
boundary[Option[T]] {
77
for item <- items do
78
if predicate(item) then break(Some(item))
79
None
80
}
81
82
val numbers = List(1, 2, 3, 4, 5)
83
val found = findFirst(numbers)(_ > 3) // Some(4)
84
85
// Complex control flow
86
def processData(data: List[String]): Either[String, List[Int]] =
87
boundary[Either[String, List[Int]]] {
88
val results = data.map { str =>
89
str.toIntOption match
90
case Some(num) => num
91
case None => break(Left(s"Invalid number: $str"))
92
}
93
Right(results)
94
}
95
```
96
97
### Utility Types
98
99
Advanced utility types for type-level programming and implicit resolution.
100
101
```scala { .api }
102
/**
103
* Negation in implicit search - provides evidence that no instance of T exists
104
* Useful for conditional compilation and type-level branching
105
*/
106
final class NotGiven[+T] private():
107
/** Get the singleton NotGiven value */
108
def value: NotGiven[Nothing] = NotGiven.value
109
110
object NotGiven:
111
/** Singleton NotGiven value */
112
val value: NotGiven[Nothing] = new NotGiven[Nothing]
113
114
/** Provide NotGiven[T] if no given T is available */
115
given [T](using NotGiven[T]): NotGiven[T] = value.asInstanceOf[NotGiven[T]]
116
```
117
118
**Usage Examples:**
119
120
```scala
121
// Conditional compilation based on available implicits
122
trait JsonEncoder[T]:
123
def encode(value: T): String
124
125
given JsonEncoder[String] = _.toString
126
given JsonEncoder[Int] = _.toString
127
128
def toJson[T](value: T)(using encoder: JsonEncoder[T]): String =
129
encoder.encode(value)
130
131
def toJsonOrFallback[T](value: T)(using encoder: NotGiven[JsonEncoder[T]]): String =
132
s"No encoder available for ${value.getClass.getSimpleName}"
133
134
// This works - encoder available
135
val jsonString = toJson("hello")
136
137
// This works - no encoder available
138
val fallback = toJsonOrFallback(List(1, 2, 3))
139
```
140
141
### Function Tupling Support
142
143
Utilities for converting between tupled and untupled function forms.
144
145
```scala { .api }
146
/**
147
* Type class for converting between regular functions and tupled functions
148
* Experimental feature for functional programming patterns
149
*/
150
sealed trait TupledFunction[F, G]:
151
/** Convert regular function to tupled form */
152
def tupled(f: F): G
153
/** Convert tupled function to regular form */
154
def untupled(g: G): F
155
156
object TupledFunction:
157
// Instances for different arities
158
given TupledFunction[A => R, Tuple1[A] => R] = ???
159
given TupledFunction[(A, B) => R, ((A, B)) => R] = ???
160
given TupledFunction[(A, B, C) => R, ((A, B, C)) => R] = ???
161
// ... more arities
162
```
163
164
**Usage Examples:**
165
166
```scala
167
// Convert between function forms
168
val add: (Int, Int) => Int = _ + _
169
val tupledAdd: ((Int, Int)) => Int = TupledFunction.tupled(add)
170
val untupledAdd: (Int, Int) => Int = TupledFunction.untupled(tupledAdd)
171
172
// Use with higher-order functions
173
val pairs = List((1, 2), (3, 4), (5, 6))
174
val sums = pairs.map(tupledAdd) // List(3, 7, 11)
175
176
// Functional composition
177
def compose[A, B, C](f: A => B, g: B => C): A => C = a => g(f(a))
178
def composeT[A, B, C](f: ((A, B)) => C): (A => B) => A => C =
179
g => a => f((a, g(a)))
180
```
181
182
### Command Line Parsing
183
184
Utilities for parsing command line arguments and options.
185
186
```scala { .api }
187
/**
188
* Command line parser with support for options, flags, and arguments
189
*/
190
object CommandLineParser:
191
/** Parse command line arguments into structured format */
192
def parse(args: Array[String]): ParseResult
193
194
/** Create parser with specific configuration */
195
def create(config: ParserConfig): CommandLineParser
196
197
/**
198
* Result of command line parsing
199
*/
200
case class ParseResult(
201
options: Map[String, String],
202
flags: Set[String],
203
arguments: List[String],
204
errors: List[String]
205
)
206
207
/**
208
* Configuration for command line parser
209
*/
210
case class ParserConfig(
211
supportedOptions: Set[String],
212
supportedFlags: Set[String],
213
allowUnknown: Boolean = false
214
)
215
```
216
217
**Usage Examples:**
218
219
```scala
220
// Basic parsing
221
val args = Array("--verbose", "--output", "result.txt", "input.txt")
222
val result = CommandLineParser.parse(args)
223
224
println(result.flags) // Set("verbose")
225
println(result.options) // Map("output" -> "result.txt")
226
println(result.arguments) // List("input.txt")
227
228
// Custom parser
229
val config = ParserConfig(
230
supportedOptions = Set("output", "config"),
231
supportedFlags = Set("verbose", "help"),
232
allowUnknown = false
233
)
234
235
val parser = CommandLineParser.create(config)
236
val customResult = parser.parse(args)
237
238
// Pattern matching on results
239
customResult match
240
case ParseResult(opts, flags, args, Nil) if flags.contains("help") =>
241
println("Help requested")
242
case ParseResult(opts, flags, args, Nil) =>
243
println(s"Processing with options: $opts")
244
case ParseResult(_, _, _, errors) =>
245
println(s"Parsing errors: ${errors.mkString(", ")}")
246
```
247
248
### Number Parsing
249
250
Type-safe number parsing from strings with compile-time validation.
251
252
```scala { .api }
253
/**
254
* Type class for parsing numbers from strings
255
* Provides compile-time validation for number formats
256
*/
257
trait FromDigits[T]:
258
/** Parse string to number, may throw exception */
259
def fromDigits(digits: String): T
260
261
object FromDigits:
262
given FromDigits[Int] = _.toInt
263
given FromDigits[Long] = _.toLong
264
given FromDigits[Float] = _.toFloat
265
given FromDigits[Double] = _.toDouble
266
given FromDigits[BigInt] = BigInt(_)
267
given FromDigits[BigDecimal] = BigDecimal(_)
268
269
/**
270
* Extension methods for string to number conversion
271
*/
272
extension (s: String)
273
/** Convert string to number of type T */
274
def parseAs[T](using FromDigits[T]): T = summon[FromDigits[T]].fromDigits(s)
275
/** Safe conversion returning Option */
276
def parseAsOption[T](using FromDigits[T]): Option[T] =
277
try Some(parseAs[T]) catch case _ => None
278
```
279
280
**Usage Examples:**
281
282
```scala
283
// Type-safe number parsing
284
val intValue = "42".parseAs[Int] // 42
285
val longValue = "123456789".parseAs[Long] // 123456789L
286
val doubleValue = "3.14159".parseAs[Double] // 3.14159
287
288
// Safe parsing with Option
289
val validInt = "42".parseAsOption[Int] // Some(42)
290
val invalidInt = "abc".parseAsOption[Int] // None
291
292
// Custom number types
293
case class UserId(value: Int)
294
295
given FromDigits[UserId] = s => UserId(s.toInt)
296
297
val userId = "12345".parseAs[UserId] // UserId(12345)
298
299
// Compile-time validation for literals
300
inline def parseAtCompileTime[T](inline s: String)(using FromDigits[T]): T =
301
inline s match
302
case _ => compiletime.constValue[T] // Simplified - actual implementation more complex
303
```
304
305
### Non-Local Returns
306
307
Support for non-local return patterns with proper resource management.
308
309
```scala { .api }
310
/**
311
* Non-local return support with proper cleanup
312
*/
313
object NonLocalReturns:
314
/** Execute block with non-local return capability */
315
def returning[T](body: ReturnThrowable[T] ?=> T): T
316
317
/** Throw non-local return with value */
318
def throwReturn[T](value: T)(using ReturnThrowable[T]): Nothing
319
320
/**
321
* Capability for non-local returns
322
*/
323
sealed class ReturnThrowable[T] extends Throwable with scala.util.control.ControlThrowable
324
```
325
326
**Usage Examples:**
327
328
```scala
329
import scala.util.control.NonLocalReturns.*
330
331
// Non-local return from nested function
332
def findFirstMatch(data: List[List[String]], target: String): Option[String] =
333
returning {
334
for
335
sublist <- data
336
item <- sublist
337
do
338
if item.contains(target) then
339
throwReturn(Some(item))
340
None
341
}
342
343
// Early exit from complex processing
344
def processComplexData(data: ComplexData): ProcessResult =
345
returning {
346
val stage1 = processStage1(data)
347
if stage1.hasErrors then throwReturn(ProcessResult.failure("Stage 1 failed"))
348
349
val stage2 = processStage2(stage1)
350
if stage2.hasErrors then throwReturn(ProcessResult.failure("Stage 2 failed"))
351
352
val stage3 = processStage3(stage2)
353
ProcessResult.success(stage3)
354
}
355
```
356
357
## Types
358
359
```scala { .api }
360
// Boundary control flow types
361
object boundary:
362
def apply[T](body: Label[T] ?=> T): T
363
def break[T](value: T)(using Label[T]): Nothing
364
def break()(using Label[Unit]): Nothing
365
366
sealed abstract class Label[-T]
367
final class Break[T](val value: T) extends Throwable
368
369
// Utility types
370
final class NotGiven[+T] private():
371
def value: NotGiven[Nothing]
372
373
sealed trait TupledFunction[F, G]:
374
def tupled(f: F): G
375
def untupled(g: G): F
376
377
// Command line parsing types
378
case class ParseResult(
379
options: Map[String, String],
380
flags: Set[String],
381
arguments: List[String],
382
errors: List[String]
383
)
384
385
case class ParserConfig(
386
supportedOptions: Set[String],
387
supportedFlags: Set[String],
388
allowUnknown: Boolean
389
)
390
391
// Number parsing types
392
trait FromDigits[T]:
393
def fromDigits(digits: String): T
394
395
// Non-local returns
396
sealed class ReturnThrowable[T] extends Throwable
397
```