Skip to content

Commit 7ce8af2

Browse files
authored
Update 2024_12_09_dependency-injection.md
set language in a code block
1 parent 8301431 commit 7ce8af2

File tree

1 file changed

+14
-19
lines changed

1 file changed

+14
-19
lines changed

2024_12_09_dependency-injection.md

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ title: Relative simple and small type-driven dependency injection
66

77
Find time to modernize dependency injection in some services. The previous version involved simply passing the context object with fields for services.
88

9-
```
9+
```Scala
1010
trait AppContext {
1111
def service1(): Service1
1212
def service2(): Service2
@@ -36,14 +36,13 @@ We will use approaches very close to what sideEffffECt describe in https://www.r
3636

3737
We will think that component `C` is provided if we can find AppProvicer[C]]
3838

39-
```
39+
```Scala
4040
trait AppContextProvider[T] {
4141
def get: T
4242
}
4343

44-
```
44+
...
4545

46-
```
4746
object AppContext {
4847

4948

@@ -55,15 +54,14 @@ def apply[T](using AppContextProvider[T]): T =
5554
}
5655
```
5756

58-
5957
If we have an implicit instance of the object, we think it's provided:
6058

6159

62-
```
60+
```Scala
6361
object AppContextProvider extends AppContextProviderLowLevel {
6462

6563

66-
given implicitInstanceProvider[T](using T): AppContextProvider[T] with {
64+
given ofGivem[T](using T): AppContextProvider[T] with {
6765
def get: T = summon[T]
6866
}
6967

@@ -76,7 +74,7 @@ Also, the usual practice for components is to define its implicit provider in th
7674

7775
Example of UserSubscription looks like:
7876

79-
```
77+
```Scala
8078
class UserSubscription(using AppContextProvider[EmailService],
8179
AppContextProvider[UserDatabase]
8280
) {
@@ -86,13 +84,10 @@ class UserSubscription(using AppContextProvider[EmailService],
8684
AppContext[EmailService].sendEmail(user, "You have been subscribed")
8785
AppContext[UserDatabase].insert(user)
8886

89-
9087
….
9188

92-
9389
}
9490

95-
9691
object UserSubscription {
9792
// boilerplate
9893
given (using AppContextProvider[EmailService],
@@ -110,7 +105,7 @@ Okay, this works, but we have to write some boilerplate. Can we have the same in
110105

111106
Sure, we can pack the provided parameter types in the tuple and use macroses for extraction.
112107

113-
```
108+
```Scala
114109
class UserSubscription(using AppContextProviders[(EmailService,UserDatabase)]) {
115110

116111

@@ -127,7 +122,7 @@ class UserSubscription(using AppContextProviders[(EmailService,UserDatabase)]) {
127122

128123
How to do this: at first, we will need a type-level machinery, which will select a first supertype of `T` from the tuple `Xs`:
129124

130-
```
125+
```Scala
131126
object TupleIndex {
132127

133128

@@ -215,7 +210,7 @@ But this will still be boilerplate: We must enumerate dependencies twice and wri
215210

216211
To minimize this kind of boilerplate, we can introduce a convention for AppContextProviderModule, which defines its dependencies in type and automatic generation of instance providers:
217212

218-
```
213+
```Scala
219214
trait AppContextProviderModule[T] {
220215

221216

@@ -264,7 +259,7 @@ Yet one facility usually needed from the dependency injection framework is cachi
264259

265260
Let’s add cache type to the AppContext:
266261

267-
```
262+
```Scala
268263
object AppContext {
269264

270265

@@ -292,7 +287,7 @@ object AppContext {
292287

293288
And let's deploy a simple convention: if the service requires `AppContext.Cache` as a dependency, then we consider this service cached. I.e., with manual setup of AppContextProvider this should look like this:
294289

295-
```
290+
```Scala
296291
object FuelUsage {
297292

298293
given (using AppContextProviders[(AppContext.Cache, Wheel, Rotor, Tail)]): AppContextProvider[FuelUsage] with
@@ -312,7 +307,7 @@ class appContextCacheClass[T] extends scala.annotation.StaticAnnotation
312307
Cache operations will follow that annotation when calculating cacheKey[T].
313308
Typical usage:
314309

315-
```
310+
```Scala
316311
trait UserSubscription
317312

318313
@appContextCacheClass[UserSubscription]
@@ -358,7 +353,7 @@ We can write a macro that should be called from the context inside a component d
358353

359354
I.e., a typical component definition will look like this:
360355

361-
```
356+
```Scala
362357
class Component(using AppContextProviders[(Dependency1,Dependency2)]) {
363358
assert(AppContextProviders.allDependenciesAreNeeded)
364359
….
@@ -373,5 +368,5 @@ With any other language, a developer can get the default most-known dependency i
373368
On the other hand, things look good. Scala's flexibility allows one to quickly develop a ‘good enough’ solution despite the fragmented ecosystem.
374369

375370

376-
Repository for this mini-framework can be found at https://github.com/rssh/scala-appcontext
371+
The repository for this mini-framework can be found at https://github.com/rssh/scala-appcontext
377372

0 commit comments

Comments
 (0)