You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/blog/2025-05-09-v0.4.0-release.md
+163-163
Original file line number
Diff line number
Diff line change
@@ -14,8 +14,170 @@ It's been a while since the last update, but the wait is over! I'm thrilled to a
14
14
15
15
This post highlights the major updates developed over the past few months, alongside some personal news.
16
16
17
-
## Rework `#[cgp_type]` Macro
18
17
18
+
## Game-Changing Improvement: Debugging is Finally Easy!
19
+
20
+
Have you ever been frustrated by cryptic CGP errors related to unsatisfied dependencies? [Previously](/blog/early-preview-announcement/#improve-error-diagnostics), this was a major barrier to `cgp`'s wider adoption, as debugging `cgp` programs was virtually impossible due to Rust hiding the information necessary to fixed the error.
21
+
22
+
Crucially, this update changes everything! The most significant improvement in v0.4.0 is that it's now significantly easier to debug `cgp` errors that arise from unsatisfied dependencies. We've developed new techniques to overcome this challenge and make Rust show all errors that were previously hidden.
23
+
24
+
25
+
### `IsProviderFor` Trait
26
+
27
+
In short, the technique works by introducing a new `IsProviderFor` trait in [#63](https://github.com/contextgeneric/cgp/pull/63), defined as follows:
The `IsProviderFor` trait itself isn't inherently complex, but it's designed to be implemented by providers with additional constraints hidden within the trait implementation. The trait then acts as a "trait-erased" trait to carry around the constraints that the provider used to implement the original provider trait.
35
+
36
+
Users of CGP don't need to understand the details of how `IsProviderFor` works, only that it's used behind the scenes by `cgp` to show better error messages.
37
+
38
+
### `CanUseComponent` Trait
39
+
40
+
Along with `IsProviderFor`, a new `CanUseComponent` blanket trait is introduced as a shorthand to check that a context's provider has implemented the `IsProviderFor` trait. It's defined as follows:
Rather than being implemented by provider types, `CanUseComponent` is instead automatically implemented by a context type. This makes it more ergonomic to reason about the implementation of a CGP component on a context.
54
+
55
+
### `#[cgp_provider]` Macro
56
+
57
+
58
+
The main change required for the new debugging to work is that users must now annotate CGP provider implementations using the `#[cgp_provider]` or `#[cgp_new_provider]` macros. For example:
59
+
60
+
```rust
61
+
#[cgp_new_provider]
62
+
impl<Context> Greeter<Context> forGreetHello
63
+
where
64
+
Context:HasName,
65
+
{
66
+
fngreet(context:&Context) {
67
+
println!("Hello, {}!", context.name());
68
+
}
69
+
}
70
+
```
71
+
72
+
The macro then generates the following `IsProviderFor` implementation, which includes the `Context: HasName` constraint within it:
The main difference between `#[cgp_provider]` and `#[cgp_new_provider]` is that `#[cgp_new_provider]` also generates the provider struct definition (e.g., `struct GreetHello;`), allowing even less code to be written by hand.
84
+
85
+
### Update to `delegate_components!`
86
+
87
+
88
+
In addition to generating `DelegateComponent` implementations, `delegate_components!` now also generates `IsProviderFor` implementations, so that `IsProviderFor` can remain working across component delegations.
Along with the `IsProviderFor` trait, [#78](https://github.com/contextgeneric/cgp/pull/78) also introduces the `check_components!` macro to allow users to write compile-time tests to check for the correctness of component wiring for a CGP context. For example:
120
+
121
+
```rust
122
+
check_components! {
123
+
CanUsePersonforPerson {
124
+
GreeterComponent,
125
+
}
126
+
}
127
+
```
128
+
129
+
130
+
The code above generates a *check trait* called `CanUsePerson`, which verifies whether the `Person` context implements the consumer trait for `GreeterComponent` (i.e., `CanGreet`):
PR [#84](https://github.com/contextgeneric/cgp/pull/84) introduces a new `delegate_and_check_components!` macro, which combines both `delegate_components!` and `check_components!`, allowing both delegation and checks within a single macro call. This is useful for the majority of simple cases, providing immediate feedback on whether the wiring works as intended.
142
+
143
+
As an example, given the following code:
144
+
145
+
```rust
146
+
delegate_and_check_components! {
147
+
CanUsePersonforPerson;
148
+
PersonComponents {
149
+
GreeterComponent:GreetHello,
150
+
}
151
+
}
152
+
```
153
+
154
+
is equivalent to writing the two separate macro calls:
155
+
156
+
```rust
157
+
delegate_components! {
158
+
PersonComponents {
159
+
GreeterComponent:GreetHello,
160
+
}
161
+
}
162
+
163
+
check_components! {
164
+
CanUsePersonforPerson {
165
+
GreeterComponent,
166
+
}
167
+
}
168
+
```
169
+
170
+
171
+
It's worth noting that in more advanced cases, it may still be necessary to call `delegate_components!` and `check_components` separately. This applies to cases where the CGP traits contain additional generic parameters, or when the new *preset* feature (discussed later) is used.
172
+
173
+
174
+
### Updated Chapter
175
+
176
+
177
+
For further details on these debugging breakthroughs, the CGP book has been updated with a [new chapter](https://patterns.contextgeneric.dev/debugging-support.html) that explains this improved debugging support in detail.
178
+
179
+
180
+
## Rework `#[cgp_type]` Macro
19
181
20
182
The `cgp_type!` macro has been reworked in [#68](https://github.com/contextgeneric/cgp/pull/68) to become an attribute macro. Previously, in v0.3.0, an abstract type was defined as:
21
183
@@ -197,168 +359,6 @@ pub trait HasConstant {
197
359
```
198
360
199
361
200
-
## Game-Changing Improvement: Debugging is Finally Easy!
201
-
202
-
Have you ever been frustrated by cryptic CGP errors related to unsatisfied dependencies? [Previously](/blog/early-preview-announcement/#improve-error-diagnostics), this was a major barrier to `cgp`'s wider adoption, as debugging `cgp` programs was virtually impossible due to Rust hiding the information necessary to fixed the error.
203
-
204
-
Crucially, this update changes everything! The most significant improvement in v0.4.0 is that it's now significantly easier to debug `cgp` errors that arise from unsatisfied dependencies. We've developed new techniques to overcome this challenge and make Rust show all errors that were previously hidden.
205
-
206
-
207
-
### `IsProviderFor` Trait
208
-
209
-
In short, the technique works by introducing a new `IsProviderFor` trait in [#63](https://github.com/contextgeneric/cgp/pull/63), defined as follows:
The `IsProviderFor` trait itself isn't inherently complex, but it's designed to be implemented by providers with additional constraints hidden within the trait implementation. The trait then acts as a "trait-erased" trait to carry around the constraints that the provider used to implement the original provider trait.
217
-
218
-
Users of CGP don't need to understand the details of how `IsProviderFor` works, only that it's used behind the scenes by `cgp` to show better error messages.
219
-
220
-
### `CanUseComponent` Trait
221
-
222
-
Along with `IsProviderFor`, a new `CanUseComponent` blanket trait is introduced as a shorthand to check that a context's provider has implemented the `IsProviderFor` trait. It's defined as follows:
Rather than being implemented by provider types, `CanUseComponent` is instead automatically implemented by a context type. This makes it more ergonomic to reason about the implementation of a CGP component on a context.
236
-
237
-
### `#[cgp_provider]` Macro
238
-
239
-
240
-
The main change required for the new debugging to work is that users must now annotate CGP provider implementations using the `#[cgp_provider]` or `#[cgp_new_provider]` macros. For example:
241
-
242
-
```rust
243
-
#[cgp_new_provider]
244
-
impl<Context> Greeter<Context> forGreetHello
245
-
where
246
-
Context:HasName,
247
-
{
248
-
fngreet(context:&Context) {
249
-
println!("Hello, {}!", context.name());
250
-
}
251
-
}
252
-
```
253
-
254
-
The macro then generates the following `IsProviderFor` implementation, which includes the `Context: HasName` constraint within it:
The main difference between `#[cgp_provider]` and `#[cgp_new_provider]` is that `#[cgp_new_provider]` also generates the provider struct definition (e.g., `struct GreetHello;`), allowing even less code to be written by hand.
266
-
267
-
### Update to `delegate_components!`
268
-
269
-
270
-
In addition to generating `DelegateComponent` implementations, `delegate_components!` now also generates `IsProviderFor` implementations, so that `IsProviderFor` can remain working across component delegations.
Along with the `IsProviderFor` trait, [#78](https://github.com/contextgeneric/cgp/pull/78) also introduces the `check_components!` macro to allow users to write compile-time tests to check for the correctness of component wiring for a CGP context. For example:
302
-
303
-
```rust
304
-
check_components! {
305
-
CanUsePersonforPerson {
306
-
GreeterComponent,
307
-
}
308
-
}
309
-
```
310
-
311
-
312
-
The code above generates a *check trait* called `CanUsePerson`, which verifies whether the `Person` context implements the consumer trait for `GreeterComponent` (i.e., `CanGreet`):
PR [#84](https://github.com/contextgeneric/cgp/pull/84) introduces a new `delegate_and_check_components!` macro, which combines both `delegate_components!` and `check_components!`, allowing both delegation and checks within a single macro call. This is useful for the majority of simple cases, providing immediate feedback on whether the wiring works as intended.
324
-
325
-
As an example, given the following code:
326
-
327
-
```rust
328
-
delegate_and_check_components! {
329
-
CanUsePersonforPerson;
330
-
PersonComponents {
331
-
GreeterComponent:GreetHello,
332
-
}
333
-
}
334
-
```
335
-
336
-
is equivalent to writing the two separate macro calls:
337
-
338
-
```rust
339
-
delegate_components! {
340
-
PersonComponents {
341
-
GreeterComponent:GreetHello,
342
-
}
343
-
}
344
-
345
-
check_components! {
346
-
CanUsePersonforPerson {
347
-
GreeterComponent,
348
-
}
349
-
}
350
-
```
351
-
352
-
353
-
It's worth noting that in more advanced cases, it may still be necessary to call `delegate_components!` and `check_components` separately. This applies to cases where the CGP traits contain additional generic parameters, or when the new *preset* feature (discussed later) is used.
354
-
355
-
356
-
### Updated Chapter
357
-
358
-
359
-
For further details on these debugging breakthroughs, the CGP book has been updated with a [new chapter](https://patterns.contextgeneric.dev/debugging-support.html) that explains this improved debugging support in detail.
360
-
361
-
362
362
## Initial Support for Datatype-Generic Programming
363
363
364
364
PR [#84](https://github.com/contextgeneric/cgp/pull/84) brings initial support for [datatype-generic programming](https://wiki.haskell.org/Generics) to Rust and CGP. A new `#[derive(HasFields)]` macro has been introduced, together with the relevant traits `HasFields`, `HasFieldsRef`, `FromFields`, `ToFields`, and `ToFieldsRef`.
0 commit comments