🦋 Welcome to the MAIN() IRC channel of the Raku Programming Language (raku.org). Log available at irclogs.raku.org/raku/live.html . If you're a beginner, you can also check out the #raku-beginner channel!
Set by lizmat on 6 September 2022.
00:36 yewscion joined 00:41 yewscion left 01:08 yewscion joined 01:14 yewscion left
SmokeMachine Voldenet: Maybe something like this? (but it needs some improvements... Ill try to take a look at it...) usercontent.irccloud-cdn.com/file/.../image.png 01:29
(that's using this: raku.land/zef:whity/Logger) 01:33
Voldenet that's not using DI, that's using magic 01:34
if X was a normal class, it shouldn't know about the DI at all 01:35
SmokeMachine what do you mean?
X is the class where the logger is being injected... 01:36
Voldenet DI should only emit some sub that'd let you write `my $x = $di.Get(X)` instead of `my $logger = Logger.new; my $x = X.new(logger => $logger)`
IMO ofc
it shouldn't alter classes anyhow 01:37
the reason is that libraries might use internal dependency injection container, not tied to the whole app
Entity framework core does this - it doesn't register all its internal classes in dotnet's DI, but has its own DI for internals 01:38
and when you have multiple models (one using mssql and one using sqlite), things work fine
SmokeMachine you don't need to alter libraries... on that example, Logger is a external library not using Injector but it's being injected anyway... 01:40
a similar example with java/kotlin: medium.com/simars/inject-loggers-i...162d02d068 01:41
01:41 yewscion joined
Voldenet SmokeMachine: what if X was in external library? 01:42
btw, @Autowiring in java is an antipattern 01:43
erm, @Autowired
current state of art is using Lombok's @RequiredArgsConstructor 01:44
…ofc micronaut's author says not to use Lombok (because annotations don't work with each other), but I digress 01:45
01:46 yewscion left
Voldenet basic idea is that the application code should be written without knowing it will use any DI 01:51
SmokeMachine I'm reading about @RequiredArgsConstructor, and if I'm reading it correctly, wouldn't it be the case to just add `is required` on your required attributes? 01:54
Voldenet it'd be `is built`
you define private fields and tell lombok to generate constructor that would initialize all `private final` fields 01:55
01:56 kylese left, kylese joined
Voldenet either way, a rough example of what I mean: 0x0.st/8xe1.raku 01:56
ofc registered method accepts anything implementing `get and get-class`, perhaps it should be a role 01:58
s/method/callable/
so it can also accept scope
also, macros probably could be used to precompile resolved subs, so nearly no hash lookups are needed 01:59
the example only highlights how I'd expect DI to be used from javacentric point of view 02:02
SmokeMachine do you really need defining that User::new? 02:04
Voldenet No, it's just as an example of using the `multi method register(::T)` 02:05
the DI could be even simpler without it
otherwise there'd no need for anything special, just dumb hash 02:06
SmokeMachine :+1
👍
Voldenet I think the container could probably know the dependencies from .^attributes alone 02:08
SmokeMachine that instantiates a new object on every .get call but easily extensible to singleton and different lifecyles... is it going to be extended, or the intention is to be that way?
I suppose it could...
Voldenet The intention is to have `class Scope { get(…) }` as well
and perhaps have registrations needing scope in separate hash 02:09
or maybe lifetime object could contain object instance tied to this lifetime
SmokeMachine do you plan to have the container as a global singleton? Or should it be local and be possible to have multiple ones? 02:11
Voldenet definitely there should be possibility to have multiple containers 02:12
I've been thinking that maybe lifetime should implement something like this `class Singleton { has $.x; method create(&fn) { $!x //= fn() }};` and every registration should have something like that 02:14
02:14 yewscion joined
SmokeMachine having multiple containers, it would be easy to make it store the object instances, and have one "global" that would work as singletons, have another one that would be created and destroyed per request, etc... and use that to control lifecycles... 02:14
Voldenet aye, that'd work
02:15 kylese left, kylese joined
SmokeMachine if you do that way I described, you would not need to implement anything lifecycle related... 02:15
Voldenet but it'd require some hackery regarding multiple scopes support 02:16
for instance, you could have a Thread-based scope, a request based scope, a container scope
SmokeMachine maybe some kind of a tree of contexts...
Voldenet it doesn't have simple parent-child relation 02:17
SmokeMachine s/contexts/containers/
Voldenet since thread id might change during one request
when using react block or await
SmokeMachine global -> request -> thread, no? 02:18
Voldenet but one thread can handle multiple requests
02:19 yewscion left
SmokeMachine multiple requests could point to the same thread? 02:19
Voldenet sure
SmokeMachine I mean, multiple request containers could be parent of the same thread container. 02:20
Voldenet but not all code will happen during the rpc request
SmokeMachine (sorry, my english do not helpme... even worst at 3:20 am...) 02:21
Voldenet np :D
if you do `start { cleanup-db(); }` that would remove stale things and try to have one connection per thread
SmokeMachine s/do/does/
Voldenet then some requests might share connection with this background job 02:22
I'm not sure how to solve that now, i'll think about it 02:23
SmokeMachine so, if I got it correctly you are saying that we could break other requests if you do what I suggested? 02:24
Voldenet yeah, other requests could get connections that aren't belonging to their current thread 02:25
it's a bit like the container itself should find the binding, then dispatch it to the proper lifetime 02:26
SmokeMachine complex... :) 02:27
Voldenet `class Singleton { has %.instances; method get-intsnces() { %.instances }}; class Thread { has @.threads; method get-instances() { @.threads[$*THREAD.id] //= {} } `
something like this…?
SmokeMachine I think something like that should work... 02:28
class Request { has %.requests; method get-instances { %.instances } } 02:29
Voldenet number of hashes sounds like performance nightmare, so maybe instances should be just array accessed by index
and then DI container should add idx to every binding 02:30
02:30 yewscion joined
SmokeMachine and probably `role Container { method get-instances {...} }` 02:30
Voldenet more like `role ContainerLifetime { method get-instances {…} }` 02:31
SmokeMachine that would make sense... but maybe that's a premature optimization?
yes
Voldenet yes, I'm evil
I always do premature optimization :)
SmokeMachine `role ContainerLifetime { has @.instances; method get-instances { @!instances } }; class Singleton does ContainerLifetime {...` if all of them will be arrays... it can be a single one, no? 02:34
Voldenet hmm, but adding the idx could quickly overallocate large arrays for requests using only one instance
02:35 yewscion left
Voldenet Yes, and in fact I'd say Singleton should have some special support, but under the hood, it could be `class Container { has Singleton $.singletons; }` 02:35
that would then be accessed by all factories using singleton lifetime 02:36
so, the pseudocode for get would be `class Container { get($key) { my $bind = self.pick-binding($key); my $l = self.pick-lifetime($bind): $l.get-instances().create($bind) }` 02:39
SmokeMachine what if you have a container merger? it wouldn't really merge the containers, but it would return a obj with all the containers you are using that time inside of it and it would know from where to get the binds you need?
Voldenet I don't think that merging containers is something implemented explicitly 02:40
I'd implement apis like `add-binding(Binding) {…}; bindings () returns Array[Binding] {…}` 02:41
or `bindings () returns Iterable {…}` but maybe it should snapshot the bindings array
and maybe `has-binding` to let users write logic for that 02:42
`for $old-container.bindings { if $new-container.has-binding($_) { warn "oh no" } else { $new-container.add-binding($_); }}` 02:44
SmokeMachine sorry, but I'm letting my imagination to travel now... what about: `class LayeredContainer { has $.parent; has %.binds; method push { ::?CLASS.new: :parent(self) }; method pop { $!parent }; method find($bind) { %!binds{$bind} // $!parent.find: $bind } }` (sorry for letting it go...) 02:47
02:47 yewscion joined
SmokeMachine that way, you would always have the last layer and could access all values you should have access to. event in multiple threads at the same time... 02:49
02:52 yewscion left
SmokeMachine something like a functional stack (github.com/FCO/Functional-Stack ) 02:52
(I'm not suggesting you you to use that module)
but if it worked like that, immutably, you would not have problems accessing it concurrently... 02:54
and each thread/request would have it's own version of containers...
please let me know how it's going. I have to go to sleep now 02:55
02:57 yewscion joined
SmokeMachine Voldenet: have a good night 03:00
03:02 yewscion left 03:13 yewscion joined 03:18 yewscion left 03:20 yewscion joined 03:25 yewscion left, Aedil joined 03:37 yewscion joined 03:42 yewscion left 03:45 kylese left 03:47 kylese joined 03:53 yewscion joined 03:58 yewscion left 04:10 yewscion joined 04:18 yewscion left
Voldenet SmokeMachine: thanks, but I was just doing chores before work - this layered container is actually how scopes should be implemented (so lifetimes that are explicitly started or ended) because scopes are hierarchical 04:18
SmokeMachine: after thinking a bit, I think that `resolve` (operation returning bind) and `get-instance { resolve(…)() }` should be separate 04:19
SmokeMachine: so unlike I wrote in my earlier example, emitting factories should attempt to resolve everything, also what should get register is the "resolve" method, not the create 04:20
which would let you do `my &handler = resolve(MyRpcMethod); route('/MyRpcMethod', { handler() })` 04:21
additionally, scopes shouldn't be fields, but they should use DI hash 04:22
04:23 leah2 left
Voldenet so the code I wrote earlier would be `class Container { resolve($key) { my $bind = self.pick-binding($key); my $l = self.resolve-class($bind.lifetime); return { $l.get-instances().create($bind) }} }` 04:23
since resolve would be a function, it could be late-bound in pessimistic cases
but in optimistic, all dependency resolving functions would be direct pointers 04:24
04:32 DarthGandalf left, DarthGandalf joined 04:48 yewscion joined 04:53 yewscion left 05:06 leah2 joined 05:58 yewscion joined 06:11 yewscion left 06:30 human-blip left 06:31 yewscion joined 06:32 human-blip joined 06:36 yewscion left 06:41 yewscion joined 06:45 yewscion left 06:51 human-blip left 06:52 human-blip joined 07:11 merp joined 07:14 yewscion joined 07:19 yewscion left 07:31 yewscion joined 07:36 yewscion left 07:48 yewscion joined
librasteve weekly: rakujourney.wordpress.com/2025/05/...avigation/ 07:49
notable6 librasteve, Noted! (weekly)
07:53 yewscion left
Xliff librasteve: Decent article. You might want expand a bit on how content() works. A before and after markup illustration would be sufficient. 07:56
08:06 wayland76 joined 08:16 yewscion joined 08:26 arkiuat left 08:27 yewscion left 08:39 arkiuat joined
lizmat librasteve: why: do for @.items.map: *kv -> (Sname, $target) { ? why not: @.items.map: *kv -> (Sname, $target) ? (aka removing "do for") 08:40
08:40 TheAthlete joined 08:44 arkiuat left 08:56 yewscion joined 09:00 apac joined 09:02 yewscion left
nijmegenzuigt anyone out there making RakuMacs xD 09:02
09:13 arkiuat joined 09:16 guifa left 09:17 yewscion joined 09:18 arkiuat left
lizmat wonders why someone would use a nick offensive to people living in Nijmegen 09:18
nijmegenzuigt we went through this before
dont you have to prepare for your 7 hour dinner? 😛 09:19
09:19 guifa joined
wayland76 Voldenet: Just checking whether I'm understanding Dependency Injection correctly, does Dependency Injection mean that you end up with Factory classes, and you ask them to make the objects you require for you? 09:19
lizmat *sigh* 09:21
09:22 yewscion left
lizmat whistlingzephyr do you have an opinion about behaviour of nijmegenzuigt here ? 09:25
nijmegenzuigt people usually do, though its often negative 😦 09:27
lizmat it's a small consolation that Arnhem will lose all their speed 09:31
wayland76 nijmegenzuigt: What does RakuMacs mean in this context? Or am I better off not asking? 09:32
09:34 yewscion joined
nijmegenzuigt just emacs but in raku :p every other editor seems to jam LLMs into everything and turn them on without asking... even zed ;_; 09:34
wayland76 Haven't seen it in nano yet :p 09:35
nijmegenzuigt and Vitesse has been close to ded so many times but if the stadium owner doesnt go it might be fully RIP
librasteve Xliff: will do … afk right now 09:37
lizmat: lemme test that when I’m back (likely red face) 09:38
note to self …. always triple check source that you post on the interweb
lizmat m: dd do for <a b c>.map: *.succ
camelia ===SORRY!=== Error while compiling <tmp>
Missing block
at <tmp>:1
------> dd do for <a b c>.map: *.succ<HERE><EOL>
expecting any of:
block or pointy block
lizmat m: dd do for <a b c>.map(*.succ) 09:39
camelia ===SORRY!=== Error while compiling <tmp>
Missing block
at <tmp>:1
------> dd do for <a b c>.map(*.succ)<HERE><EOL>
expecting any of:
block or pointy block
lizmat meh
09:39 yewscion left
wayland76 For those wondering about Dependency Injection, I'm finding the following useful: martinfowler.com/articles/injection.html 09:40
09:47 arkiuat joined 09:49 yewscion joined 09:51 arkiuat left, apac left
librasteve good article … thanks for the link … HARC stack can do any raku DI tool you like. i just personally own to the DIY approach I linked to above - timtowdi 09:54
09:54 yewscion left
lizmat and yet another Rakudo Weekly News hits the Net: rakudoweekly.blog/2025/05/26/2025-...rcigation/ 09:57
09:58 NijmegenRocks joined 09:59 NijmegenRocks left 10:04 apac joined 10:06 yewscion joined 10:13 yewscion left 10:16 apac left 10:19 yewscion joined 10:22 Sgeo left 10:23 arkiuat joined, apac joined 10:28 yewscion left 10:32 arkiuat left
wayland76 librasteve: Can you give examples of existing "raku DI tools"? 10:34
10:39 yewscion joined
nijmegenzuigt ChatGPT SteveTM 10:44
10:45 yewscion left 10:46 arkiuat joined 10:50 arkiuat left 10:58 yewscion joined
wayland76 Good idea. chatgpt.com/share/683449ce-8088-80...540e3517f2 11:01
11:03 yewscion left
wayland76 Although half of that is hallucination. 11:04
Voldenet wayland76: well, dependency injection means that the class requests specific classes/roles/interfaces, but something else specifies how those dependencies are created/provided - dependency injection container is a tool used to define that
wayland76 Does the DBIish model (an interface class, and a number of implementation classes, and you pass in the implementation name as a parameter to the Interface when creating it) count as Dependency Injection? 11:06
Voldenet but you don't have to end up with some central point, that's why Injector provided dependency injection but it did that very differently
11:06 arkiuat joined
wayland76 Ah, a kind of "Object to help create the object" then? 11:10
Voldenet the main point is to not do .new on things, but instead have objects created always 11:11
11:11 arkiuat left
Voldenet so… I'd say that DBIish doesn't do DI, you register some drivers, but ultimately it somehow picks the connection 11:14
11:15 yewscion joined
Voldenet without di connect method does .install-driver, with di, it would require driver as parameter 11:16
with DI it'd require you to use the proper class implementing driver `DBIish.connect(DBIIsh::Pg.new(…))` 11:18
wayland76 So you're saying that, instead of requiring the name of the driver, it would require an actual object of the driver? 11:19
Voldenet yeah
I don't know if that would be useful in the context, but it isn't significantly different 11:24
11:24 yewscion left
wayland76 I think that, in the DBIish case, we get most of the advantages without the disadvantage of having to create the objects. 11:25
11:27 topnep left
Voldenet pure DI tries to push "I never create objects" to the limit of "container creates everything for me", though it mostly works with all the other creational patterns 11:28
so I often put abstract factories into DI and then request those factories to use somewhere else, without DI knowing 11:29
wayland76 Yep. I can see that. Hmm. I wonder how they create Exceptions :p 11:30
Voldenet *sigh* Yes
`ExceptionProvider.createThing()` instead of `new Exception("thing")` 11:31
honestly it's too puristic for me - there are pros 11:32
like you can, depending on the creation context, know what kind of exception throw in the same place (with details or without)
11:34 topnep joined
Voldenet but imagine requesting ExceptionProvider and Logger every piece of code, it could become madness quick 11:34
wayland76 Yes. I think the concept of easily interchangeable Implementations is a good idea, but DI is just one method of achieving that. 11:35
Voldenet what DI actually helps doing best is testing 11:36
11:36 yewscion joined
Voldenet you know what you need to mock, there's no providers or dynamic variables to register 11:36
imagine testing code, where someone liberally uses `my $dbh = DBIish.connect("Pg"` in 20 methods, a horror 11:38
11:39 arkiuat joined 11:40 yewscion left
wayland76 Agreed, but if they did `my $dbh = DBIish.connect($backend` in 20 methods, and the string in $backend got passed around the same way that the injected dependency did, it'd solve the same problem, I think. 11:49
Voldenet …and the string $backend could be stored as dependency ;) 11:51
DI would deal with it entirely differently, it'd simply register factory method for DBDish::Connection and do the connect there 11:52
eh, but in that case it'd probably also need to do .dispose afterwards 12:00
wayland76 Yep. I'm heading to bed. Have a good day/night, everyone :) o/
12:07 yewscion joined 12:16 yewscion left 12:26 yewscion joined
SmokeMachine So bizarre! Chat GPT suggests copying Red to DI and ignores Injector… 12:26
12:31 yewscion left
SmokeMachine Voldenet: I was thinking… how do you plan to pass the container around? I mean: what if a internal class needs it? Or it shouldn’t? 12:32
If they were using Red, they wouldn’t need to .connect on 20 methods (just a joke) 12:34
Voldenet resolved factory should accept DI instance, but not provide its own imo
because resolved factories get only DI instance as an argument 12:35
so, everything only gets the container or scope (that should know its parent scope or container) 12:36
it's certainly possible to pass the original DI instance around, since returned factory can hold that object, but I'd rather do that as an exception 12:38
if it's ever needed 12:39
Xliff m: my $a = Promise.in(10).then(-> { say "Boo" } 13:05
camelia ===SORRY!=== Error while compiling <tmp>
Unable to parse expression in argument list; couldn't find final ')' (corresponding starter was at line 1)
at <tmp>:1
------> a = Promise.in(10).then(-> { say "Boo" }<HERE><EOL>
expecting any of:
Xliff m: my $a = Promise.in(10).then(-> { say "Boo" })
camelia ( no output )
Xliff m: my $a = Promise.in(10).then(-> { say "Boo" }); sleep 6
camelia ( no output )
Xliff m: my $a = Promise.in(10).then(-> { say "Boo" }); await $a
camelia An operation first awaited:
in block <unit> at <tmp> line 1

Died with the exception:
Too many positionals passed; expected 0 arguments but got 1
in block at <tmp> line 1
13:06
Xliff m: my $a = Promise.in(10).then({ say "Boo" }); await $a
camelia Boo
Xliff m: my $a = Promise.in(5).then({ say "Boo" }); start { await $a }; $a.break
camelia Access denied to keep/break this Promise; already vowed
in block <unit> at <tmp> line 1
Xliff How could I abort the promise in $a?
lizmat you can't 13:10
but if you instead use $*SCHEDULER.cue, you can: docs.raku.org/routine/cue
Voldenet you don't, you instead ask methods to cancel themselves when the bool is set 13:19
…or use the second Promise
m: my $cancel = Promise.new; my $a = Promise.anyof(Promise.in(5), $cancel).then({ say "Boo" }); Promise.in(1).then({ $cancel.vow.break("timeout"); }); my $n = now; await $a; say now - $n 13:20
camelia Boo
1.015403736
Voldenet (then gets executed after 1s instead of 5, but you can check the status of the promise)
librasteve lizmat: i have reviewed my code do for @.items.map: *.kv -> ($name, $target) {} and I think it's right ... to paraphrase it's saying "take each pair in @.items, and map its .kv to $name, $target and then do something" ... so the for is iterating the @.items list and the map is iterating over the kv 13:21
there may be better way to write that - but its not that I duplicated the iterator
Voldenet m: my $cancel = False; my $p = Promise.new; my $x = $p.then({ die "cancelled" if $cancel; say "Boo" }); $cancel = True; $p.vow.keep(Any); await $x 13:23
camelia An operation first awaited:
in block <unit> at <tmp> line 1

Died with the exception:
cancelled
in block at <tmp> line 1
Voldenet alternative - voluntary cancellation
librasteve btw still not happy with what i wrote --- noodling 13:27
lizmat librasteve @.items.kv -> $name,$target { perhaps ? 13:31
librasteve @.items.kv.map: -> $name,$target { I meant :-) 13:33
librasteve i tried the first already - didn't work
lizmat yeah, because it failed the .map 13:34
or maybe I'm not grokking what you want to produce :-( 13:35
afk for a few hours& 13:41
nijmegenzuigt 🙂
librasteve .ignore 13:45
14:23 yewscion joined 14:27 yewscion left 14:29 wayland76 left, wayland joined
melezhik. o/ 14:43
I have already asked . But one more time ))) if someone would review this Raku/Regexp guide for none Raku users I would appreciate it. git.resf.org/melezhik/sparrow_task.../README.md 14:44
Starting from Raku regexps section
antononcube Cannot open it... 14:45
melezhik. One may disregard Sparrow specific
antononcube Ok, it did open, after 20 seconds. 14:46
melezhik. Yeah. Theirs server maybe abit slow
Starting actually from this - git.resf.org/melezhik/sparrow_task...xpressions 14:47
nijmegenzuigt anton, I was about to say you dont have anything with voronoi diagrams but you have so many libraries to make them in your repos xD 16:24
math lord
antononcube It is in my soon-TODO list implement Voronoi diagrams in Raku. (In order to use them in Geographics computations.) 16:37
Mostly, I am not sure how to visualize them. "JavaScripdt::D3" needs a fair amount of work (both design and implementation) to make plots with collections of graphics primitives. (Points, segments, polygons, etc.) 16:39
16:46 yewscion joined 16:50 yewscion left
nijmegenzuigt thats more how you want them to be rendered, no? 16:50
whether you start out with a grid and calculate a Voronoi grid out of that or you can let them expand in near distance 16:52
16:52 Sgeo joined
I do remember trying to make a civ style globe with voronoi grid but that was beyond my skill level then 16:54
maybe stil is 🥲
antononcube The actual computations of voronoi-mesh and its dual delaunay-mesh is not that hard. What is hard for me to figure out is: (i) which package should have those implementations, (ii) how to visualize those meshes, using which packages. 16:56
nijmegenzuigt ah ye 16:57
that makes more sense xD
antononcube Since, delaunay-mesh is "just" a graph, it can be readily visualized with "JavaScripdt::D3" and "Graph".
Also, I am not sure should I handle just 1D and 2D cases, or go higher 3D and nD. 16:58
nijmegenzuigt I am used to more game-programming hackey ways; mathematically correct because It Just WorksTM but suboptimal 16:59
😎
on a legit graph you have so many ways to do it :/ 17:00
a 2D graph I mean 17:01
like you can have convexed shapes of Voronoi cells I guess 17:06
I avoid that like a plague
would love to see it if you did make do end up making it tho 🙂 17:07
just like my countryman, I'll stick with the superior Mondrian diagram. Just rectangles ez. 17:13
antononcube 🤷‍♂️ 🪟 17:24
nijmegenzuigt excuse me bro
🟥⬜🟦🟥🟧 17:25
SmokeMachine librasteve: I commented your PR: github.com/FCO/Cromponent/pull/12#...2868836422 18:10
19:34 TheAthlete left
librasteve SmokeMachine: thanks - my comments to your comments are now done 20:01
20:41 apac left 20:50 apac joined 20:59 Aedil left 22:43 apac left 23:38 yewscion joined 23:44 yewscion left, yewscion joined 23:51 yewscion left