firefly-compiler 0.5.39 → 0.5.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.hintrc +4 -4
- package/.vscode/settings.json +4 -4
- package/bin/Release.ff +157 -157
- package/bin/firefly.mjs +1 -1
- package/compiler/Builder.ff +275 -275
- package/compiler/Compiler.ff +234 -234
- package/compiler/Dependencies.ff +186 -186
- package/compiler/DependencyLock.ff +17 -17
- package/compiler/JsEmitter.ff +1437 -1437
- package/compiler/LspHook.ff +202 -202
- package/compiler/ModuleCache.ff +178 -178
- package/compiler/Workspace.ff +88 -88
- package/core/.firefly/include/package.json +5 -5
- package/core/.firefly/package.ff +2 -2
- package/core/Any.ff +25 -25
- package/core/Array.ff +298 -298
- package/core/Atomic.ff +63 -63
- package/core/Box.ff +7 -7
- package/core/BrowserSystem.ff +40 -40
- package/core/BuildSystem.ff +156 -156
- package/core/Crypto.ff +94 -94
- package/core/Equal.ff +41 -41
- package/core/Error.ff +25 -25
- package/core/HttpClient.ff +142 -142
- package/core/Instant.ff +24 -24
- package/core/Js.ff +305 -305
- package/core/JsSystem.ff +135 -135
- package/core/Json.ff +423 -423
- package/core/List.ff +482 -482
- package/core/Lock.ff +108 -108
- package/core/NodeSystem.ff +198 -198
- package/core/Ordering.ff +160 -160
- package/core/Path.ff +377 -378
- package/core/Queue.ff +90 -90
- package/core/Random.ff +140 -140
- package/core/RbMap.ff +216 -216
- package/core/Show.ff +44 -44
- package/core/SourceLocation.ff +68 -68
- package/core/Task.ff +165 -165
- package/experimental/benchmarks/ListGrab.ff +23 -23
- package/experimental/benchmarks/ListGrab.java +55 -55
- package/experimental/benchmarks/Pyrotek45.ff +30 -30
- package/experimental/benchmarks/Pyrotek45.java +64 -64
- package/experimental/bidirectional/Bidi.ff +88 -88
- package/experimental/lines/Main.ff +40 -40
- package/experimental/random/Index.ff +53 -53
- package/experimental/random/Process.ff +120 -120
- package/experimental/random/RunLength.ff +65 -65
- package/experimental/random/Scrape.ff +51 -51
- package/experimental/random/Symbols.ff +73 -73
- package/experimental/random/Tensor.ff +52 -52
- package/experimental/random/Units.ff +36 -36
- package/experimental/s3/S3TestAuthorizationHeader.ff +39 -39
- package/experimental/s3/S3TestPut.ff +16 -16
- package/experimental/tests/TestJson.ff +26 -26
- package/firefly.sh +0 -0
- package/fireflysite/.firefly/package.ff +4 -4
- package/fireflysite/CommunityOverview.ff +20 -20
- package/fireflysite/CountingButtonDemo.ff +58 -58
- package/fireflysite/DocumentParser.ff +325 -325
- package/fireflysite/ExamplesOverview.ff +40 -40
- package/fireflysite/FrontPage.ff +344 -344
- package/fireflysite/GettingStarted.ff +45 -45
- package/fireflysite/Guide.ff +456 -456
- package/fireflysite/Main.ff +163 -163
- package/fireflysite/MatchingPasswordsDemo.ff +82 -82
- package/fireflysite/PackagesOverview.ff +49 -49
- package/fireflysite/PostgresqlDemo.ff +34 -34
- package/fireflysite/ReferenceAll.ff +18 -18
- package/fireflysite/ReferenceIntroduction.ff +11 -11
- package/fireflysite/Styles.ff +567 -567
- package/fireflysite/Test.ff +121 -121
- package/fireflysite/assets/markdown/reference/BaseTypes.md +209 -209
- package/fireflysite/assets/markdown/reference/EmittedJavascript.md +65 -65
- package/fireflysite/assets/markdown/reference/Exceptions.md +101 -101
- package/fireflysite/assets/markdown/reference/FunctionsAndMethods.md +364 -364
- package/fireflysite/assets/markdown/reference/JavascriptInterop.md +235 -235
- package/fireflysite/assets/markdown/reference/ModulesAndPackages.md +162 -162
- package/fireflysite/assets/markdown/reference/OldStructuredConcurrency.md +48 -48
- package/fireflysite/assets/markdown/reference/PatternMatching.md +224 -224
- package/fireflysite/assets/markdown/reference/StatementsAndExpressions.md +86 -86
- package/fireflysite/assets/markdown/reference/StructuredConcurrency.md +99 -99
- package/fireflysite/assets/markdown/reference/TraitsAndInstances.md +100 -100
- package/fireflysite/assets/markdown/reference/UserDefinedTypes.md +184 -184
- package/fireflysite/assets/markdown/scratch/ControlFlow.md +136 -136
- package/fireflysite/assets/markdown/scratch/Toc.md +40 -40
- package/lsp/.firefly/package.ff +1 -1
- package/lsp/CompletionHandler.ff +827 -827
- package/lsp/Handler.ff +714 -714
- package/lsp/HoverHandler.ff +79 -79
- package/lsp/LanguageServer.ff +272 -272
- package/lsp/SignatureHelpHandler.ff +55 -55
- package/lsp/SymbolHandler.ff +181 -181
- package/lsp/TestReferences.ff +17 -17
- package/lsp/TestReferencesCase.ff +7 -7
- package/lsp/stderr.txt +1 -1
- package/lsp/stdout.txt +34 -34
- package/lux/.firefly/package.ff +1 -1
- package/lux/Css.ff +648 -648
- package/lux/CssTest.ff +48 -48
- package/lux/Lux.ff +608 -608
- package/lux/LuxEvent.ff +79 -79
- package/lux/Main.ff +123 -123
- package/lux/Main2.ff +143 -143
- package/lux/TestDry.ff +28 -28
- package/output/js/ff/compiler/Builder.mjs +36 -36
- package/output/js/ff/core/Path.mjs +0 -2
- package/package.json +1 -1
- package/rpc/.firefly/package.ff +1 -1
- package/rpc/Rpc.ff +70 -70
- package/s3/.firefly/package.ff +1 -1
- package/s3/S3.ff +92 -92
- package/vscode/LICENSE.txt +21 -21
- package/vscode/Prepublish.ff +15 -15
- package/vscode/README.md +16 -16
- package/vscode/client/package-lock.json +544 -544
- package/vscode/client/package.json +22 -22
- package/vscode/client/src/extension.ts +104 -104
- package/vscode/icons/firefly-icon.svg +10 -10
- package/vscode/language-configuration.json +61 -61
- package/vscode/package-lock.json +3623 -3623
- package/vscode/package.json +1 -1
- package/vscode/snippets.json +241 -241
- package/vscode/syntaxes/firefly-markdown-injection.json +45 -45
- package/webserver/.firefly/include/package.json +5 -5
- package/webserver/.firefly/package.ff +2 -2
- package/webserver/WebServer.ff +647 -647
- package/websocket/.firefly/package.ff +1 -1
- package/websocket/WebSocket.ff +100 -100
|
@@ -1,99 +1,99 @@
|
|
|
1
|
-
# Structured concurrency
|
|
2
|
-
|
|
3
|
-
Firefly has a lightweight task system that supports structured concurrency and cancellation.
|
|
4
|
-
|
|
5
|
-
Tasks are structured in a parent-child relationship, where the parent scope waits for all its child tasks to complete before proceeding.
|
|
6
|
-
|
|
7
|
-
If the parent task or a sibling subtask fails with an uncaught exception, the other subtasks are cancelled.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# Waiting for results
|
|
11
|
-
|
|
12
|
-
A simple use case is to concurrently run some tasks and waiting for their results.
|
|
13
|
-
This can be done without explicitly spawning tasks, as there's a utility method `task.mapList()` for this:
|
|
14
|
-
|
|
15
|
-
```firefly
|
|
16
|
-
let results = system.mainTask().mapList(urls) {url =>
|
|
17
|
-
system.httpClient().get(url) {_.readText()}
|
|
18
|
-
}
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
This fetches all of the URLs concurrently.
|
|
22
|
-
If any fetch throws an exception, the other fetches are cancelled and `task.mapList()` rethrows an exception.
|
|
23
|
-
Otherwise, the list of results is returned.
|
|
24
|
-
|
|
25
|
-
Similarly, `task.raceList()` can be used to run some tasks concurrently, wait for the first one to complete, and cancel the others.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
# Spawning tasks
|
|
29
|
-
|
|
30
|
-
A slightly more advanced use case is handling requests concurrently. It might look like this:
|
|
31
|
-
|
|
32
|
-
```firefly
|
|
33
|
-
while {True} {
|
|
34
|
-
let request = waitForRequest()
|
|
35
|
-
system.mainTask().spawn {subtask =>
|
|
36
|
-
handleRequest(subtask, request)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
The infinite loop here calls some function to wait for the next request.
|
|
42
|
-
Then it spawns a subtask to handle the request, and loops back to waiting for the next request.
|
|
43
|
-
The subtask executes concurrently, and thus doesn't block the loop while the request is being handled.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
# Channels
|
|
47
|
-
|
|
48
|
-
Concurrently running tasks may need to communicate while executing.
|
|
49
|
-
One mechanism for inter-task communication is the `Channel[T]` type, which represents an unbuffered multi-producer multi-consumer channel for messages of type `T`.
|
|
50
|
-
|
|
51
|
-
A function to read URLs from a channel, fetch JSON from those URLs, and write the results to another channel could look like this:
|
|
52
|
-
|
|
53
|
-
```firefly
|
|
54
|
-
fetchTask(in: Channel[String], out: Channel[Json]) {
|
|
55
|
-
while {True} {
|
|
56
|
-
let url = in.read()
|
|
57
|
-
let result = system.httpClient().get(url) {_.readJson()}
|
|
58
|
-
out.write(result)
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
The `in.read()` call waits until there's a task ready to write to the `in` channel.
|
|
64
|
-
Similarly, the `out.write()` call waits until there's a task ready to read from the `out` channel.
|
|
65
|
-
|
|
66
|
-
To do multiple requests concurrently, spawn multiple instances of the task:
|
|
67
|
-
|
|
68
|
-
```firefly
|
|
69
|
-
let in = system.mainTask().channel()
|
|
70
|
-
let out = system.mainTask().channel()
|
|
71
|
-
1.to(3).each {_ =>
|
|
72
|
-
system.mainTask().spawn {_ =>
|
|
73
|
-
fetchTask(in, out)
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Consider calling an API that either returns `{value: ...}` where `...` is some number, or `{add: ...}` where `...` is a list of API URLs to add up to a total.
|
|
79
|
-
A first attempt could be adding the following code:
|
|
80
|
-
|
|
81
|
-
```firefly
|
|
82
|
-
mutable total = 0
|
|
83
|
-
in.write("https://example.com/my-api")
|
|
84
|
-
while {True} {
|
|
85
|
-
let json = out.read()
|
|
86
|
-
json.field("value").map {total += _.grabInt()}.else {
|
|
87
|
-
let urls = json.field("add").map {_.grabArray().map {_.grabString()}}
|
|
88
|
-
urls.each {url =>
|
|
89
|
-
in.write(url)
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
However, there are two problems here:
|
|
96
|
-
|
|
97
|
-
* If all the fetch tasks are waiting to write to the `out` channel, `in.write(url)` will block forever.
|
|
98
|
-
* There's no logic to discover that there are no API calls left to do, so the `total` will never be reported.
|
|
99
|
-
|
|
1
|
+
# Structured concurrency
|
|
2
|
+
|
|
3
|
+
Firefly has a lightweight task system that supports structured concurrency and cancellation.
|
|
4
|
+
|
|
5
|
+
Tasks are structured in a parent-child relationship, where the parent scope waits for all its child tasks to complete before proceeding.
|
|
6
|
+
|
|
7
|
+
If the parent task or a sibling subtask fails with an uncaught exception, the other subtasks are cancelled.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# Waiting for results
|
|
11
|
+
|
|
12
|
+
A simple use case is to concurrently run some tasks and waiting for their results.
|
|
13
|
+
This can be done without explicitly spawning tasks, as there's a utility method `task.mapList()` for this:
|
|
14
|
+
|
|
15
|
+
```firefly
|
|
16
|
+
let results = system.mainTask().mapList(urls) {url =>
|
|
17
|
+
system.httpClient().get(url) {_.readText()}
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
This fetches all of the URLs concurrently.
|
|
22
|
+
If any fetch throws an exception, the other fetches are cancelled and `task.mapList()` rethrows an exception.
|
|
23
|
+
Otherwise, the list of results is returned.
|
|
24
|
+
|
|
25
|
+
Similarly, `task.raceList()` can be used to run some tasks concurrently, wait for the first one to complete, and cancel the others.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# Spawning tasks
|
|
29
|
+
|
|
30
|
+
A slightly more advanced use case is handling requests concurrently. It might look like this:
|
|
31
|
+
|
|
32
|
+
```firefly
|
|
33
|
+
while {True} {
|
|
34
|
+
let request = waitForRequest()
|
|
35
|
+
system.mainTask().spawn {subtask =>
|
|
36
|
+
handleRequest(subtask, request)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The infinite loop here calls some function to wait for the next request.
|
|
42
|
+
Then it spawns a subtask to handle the request, and loops back to waiting for the next request.
|
|
43
|
+
The subtask executes concurrently, and thus doesn't block the loop while the request is being handled.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Channels
|
|
47
|
+
|
|
48
|
+
Concurrently running tasks may need to communicate while executing.
|
|
49
|
+
One mechanism for inter-task communication is the `Channel[T]` type, which represents an unbuffered multi-producer multi-consumer channel for messages of type `T`.
|
|
50
|
+
|
|
51
|
+
A function to read URLs from a channel, fetch JSON from those URLs, and write the results to another channel could look like this:
|
|
52
|
+
|
|
53
|
+
```firefly
|
|
54
|
+
fetchTask(in: Channel[String], out: Channel[Json]) {
|
|
55
|
+
while {True} {
|
|
56
|
+
let url = in.read()
|
|
57
|
+
let result = system.httpClient().get(url) {_.readJson()}
|
|
58
|
+
out.write(result)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The `in.read()` call waits until there's a task ready to write to the `in` channel.
|
|
64
|
+
Similarly, the `out.write()` call waits until there's a task ready to read from the `out` channel.
|
|
65
|
+
|
|
66
|
+
To do multiple requests concurrently, spawn multiple instances of the task:
|
|
67
|
+
|
|
68
|
+
```firefly
|
|
69
|
+
let in = system.mainTask().channel()
|
|
70
|
+
let out = system.mainTask().channel()
|
|
71
|
+
1.to(3).each {_ =>
|
|
72
|
+
system.mainTask().spawn {_ =>
|
|
73
|
+
fetchTask(in, out)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Consider calling an API that either returns `{value: ...}` where `...` is some number, or `{add: ...}` where `...` is a list of API URLs to add up to a total.
|
|
79
|
+
A first attempt could be adding the following code:
|
|
80
|
+
|
|
81
|
+
```firefly
|
|
82
|
+
mutable total = 0
|
|
83
|
+
in.write("https://example.com/my-api")
|
|
84
|
+
while {True} {
|
|
85
|
+
let json = out.read()
|
|
86
|
+
json.field("value").map {total += _.grabInt()}.else {
|
|
87
|
+
let urls = json.field("add").map {_.grabArray().map {_.grabString()}}
|
|
88
|
+
urls.each {url =>
|
|
89
|
+
in.write(url)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
However, there are two problems here:
|
|
96
|
+
|
|
97
|
+
* If all the fetch tasks are waiting to write to the `out` channel, `in.write(url)` will block forever.
|
|
98
|
+
* There's no logic to discover that there are no API calls left to do, so the `total` will never be reported.
|
|
99
|
+
|
|
@@ -1,100 +1,100 @@
|
|
|
1
|
-
# Traits and instances
|
|
2
|
-
|
|
3
|
-
A trait defines an open set of types that support a common set of functions.
|
|
4
|
-
For example, here's a trait for shapes with a common function to compute the area:
|
|
5
|
-
|
|
6
|
-
```firefly
|
|
7
|
-
trait T: Shape {
|
|
8
|
-
area(shape: T): Float
|
|
9
|
-
}
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
The function becomes a top level function `area[T: Shape](shape: T): Float`.
|
|
13
|
-
Here `T` is a bounded type parameter: It can only be instantiated to a type that has an instance of the `Shape` trait.
|
|
14
|
-
|
|
15
|
-
Consider these two types that would be good candidates for having an instance of the `Shape` trait:
|
|
16
|
-
|
|
17
|
-
```firefly
|
|
18
|
-
data Circle(radius: Float)
|
|
19
|
-
data Rectangle(width: Float, height: Float)
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Only types defined with the `data` or `newtype` keyword can have trait instances.
|
|
23
|
-
|
|
24
|
-
Instances for these types can be created with the `instance` keyword as follows:
|
|
25
|
-
|
|
26
|
-
```firefly
|
|
27
|
-
instance Circle: Shape {
|
|
28
|
-
area(shape: Circle): Float {
|
|
29
|
-
Float.pi() * (shape.radius ^ 2.0)
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
instance Rectangle: Shape {
|
|
34
|
-
area(shape: Rectangle): Float {
|
|
35
|
-
shape.width * shape.height
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Each instance provides an implementation of `area` specific to the type.
|
|
41
|
-
|
|
42
|
-
Here's an example of how to define a normal top level function with a bounded type parameter:
|
|
43
|
-
|
|
44
|
-
```firefly
|
|
45
|
-
printArea[T: Shape](shape: T) {
|
|
46
|
-
Log.trace("Area: " + area(shape))
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
printArea(Circle(0.0)) // Prints "Area: 0"
|
|
50
|
-
printArea(Rectangle(5.0, 6.0)) // Prints "Area: 30"
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Multiple bounds are separated by colons, e.g. `foo[T: Bar: Baz]` means that `T` must have instances for both `Bar` and `Baz`.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
# Traits with type parameters
|
|
57
|
-
|
|
58
|
-
Traits can have type parameters:
|
|
59
|
-
|
|
60
|
-
```firefly
|
|
61
|
-
trait I: Rpc[O] {}
|
|
62
|
-
|
|
63
|
-
instance MyMessage: Rpc[Int] {}
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
The choice of `I` fully determines `O` - in this case, if `I` is `MyMessage`, then `O` is `Int`.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
# Automatic traits
|
|
70
|
-
|
|
71
|
-
If instances for the following traits are not explicitly defined, they will be generated automatically.
|
|
72
|
-
This only applies to types defined with the `data` or `newtype` keyword.
|
|
73
|
-
|
|
74
|
-
```firefly
|
|
75
|
-
// Used for == !=
|
|
76
|
-
trait T: Equal {
|
|
77
|
-
equals(x: T, y: T): Bool
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Used for < > <= >= and sorting
|
|
81
|
-
trait T: Order {
|
|
82
|
-
compare(x: T, y: T): Ordering
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Used to display values for debugging
|
|
86
|
-
trait T: Show {
|
|
87
|
-
show(value: T): String
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Used for binary serialization
|
|
91
|
-
trait T: Serializable {
|
|
92
|
-
serializeUsing(serialization: Serialization, value: T): Unit
|
|
93
|
-
deserializeUsing(serialization: Serialization): T
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Used for throwing and catching exceptions
|
|
97
|
-
trait T: HasAnyTag {
|
|
98
|
-
anyTag(): AnyTag[T]
|
|
99
|
-
}
|
|
100
|
-
```
|
|
1
|
+
# Traits and instances
|
|
2
|
+
|
|
3
|
+
A trait defines an open set of types that support a common set of functions.
|
|
4
|
+
For example, here's a trait for shapes with a common function to compute the area:
|
|
5
|
+
|
|
6
|
+
```firefly
|
|
7
|
+
trait T: Shape {
|
|
8
|
+
area(shape: T): Float
|
|
9
|
+
}
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The function becomes a top level function `area[T: Shape](shape: T): Float`.
|
|
13
|
+
Here `T` is a bounded type parameter: It can only be instantiated to a type that has an instance of the `Shape` trait.
|
|
14
|
+
|
|
15
|
+
Consider these two types that would be good candidates for having an instance of the `Shape` trait:
|
|
16
|
+
|
|
17
|
+
```firefly
|
|
18
|
+
data Circle(radius: Float)
|
|
19
|
+
data Rectangle(width: Float, height: Float)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Only types defined with the `data` or `newtype` keyword can have trait instances.
|
|
23
|
+
|
|
24
|
+
Instances for these types can be created with the `instance` keyword as follows:
|
|
25
|
+
|
|
26
|
+
```firefly
|
|
27
|
+
instance Circle: Shape {
|
|
28
|
+
area(shape: Circle): Float {
|
|
29
|
+
Float.pi() * (shape.radius ^ 2.0)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
instance Rectangle: Shape {
|
|
34
|
+
area(shape: Rectangle): Float {
|
|
35
|
+
shape.width * shape.height
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Each instance provides an implementation of `area` specific to the type.
|
|
41
|
+
|
|
42
|
+
Here's an example of how to define a normal top level function with a bounded type parameter:
|
|
43
|
+
|
|
44
|
+
```firefly
|
|
45
|
+
printArea[T: Shape](shape: T) {
|
|
46
|
+
Log.trace("Area: " + area(shape))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
printArea(Circle(0.0)) // Prints "Area: 0"
|
|
50
|
+
printArea(Rectangle(5.0, 6.0)) // Prints "Area: 30"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Multiple bounds are separated by colons, e.g. `foo[T: Bar: Baz]` means that `T` must have instances for both `Bar` and `Baz`.
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# Traits with type parameters
|
|
57
|
+
|
|
58
|
+
Traits can have type parameters:
|
|
59
|
+
|
|
60
|
+
```firefly
|
|
61
|
+
trait I: Rpc[O] {}
|
|
62
|
+
|
|
63
|
+
instance MyMessage: Rpc[Int] {}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The choice of `I` fully determines `O` - in this case, if `I` is `MyMessage`, then `O` is `Int`.
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# Automatic traits
|
|
70
|
+
|
|
71
|
+
If instances for the following traits are not explicitly defined, they will be generated automatically.
|
|
72
|
+
This only applies to types defined with the `data` or `newtype` keyword.
|
|
73
|
+
|
|
74
|
+
```firefly
|
|
75
|
+
// Used for == !=
|
|
76
|
+
trait T: Equal {
|
|
77
|
+
equals(x: T, y: T): Bool
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Used for < > <= >= and sorting
|
|
81
|
+
trait T: Order {
|
|
82
|
+
compare(x: T, y: T): Ordering
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Used to display values for debugging
|
|
86
|
+
trait T: Show {
|
|
87
|
+
show(value: T): String
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Used for binary serialization
|
|
91
|
+
trait T: Serializable {
|
|
92
|
+
serializeUsing(serialization: Serialization, value: T): Unit
|
|
93
|
+
deserializeUsing(serialization: Serialization): T
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Used for throwing and catching exceptions
|
|
97
|
+
trait T: HasAnyTag {
|
|
98
|
+
anyTag(): AnyTag[T]
|
|
99
|
+
}
|
|
100
|
+
```
|