From db3236b8cd04945d87fb02e52191ca77fcc8008d Mon Sep 17 00:00:00 2001 From: Pagwin Date: Thu, 1 Sep 2022 11:23:31 -0400 Subject: [PATCH 1/3] starting work on the serenity article --- content/blog/serenity_why.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 content/blog/serenity_why.md diff --git a/content/blog/serenity_why.md b/content/blog/serenity_why.md new file mode 100644 index 0000000..41ff9c1 --- /dev/null +++ b/content/blog/serenity_why.md @@ -0,0 +1,12 @@ +--- + +title: "" + +description: "" + +date: 2022-09-01 + +draft: true + +--- + From 3312a04f4302ba4e9b7f9fd9812b3f2d345465ad Mon Sep 17 00:00:00 2001 From: Pagwin Date: Thu, 1 Sep 2022 13:03:06 -0400 Subject: [PATCH 2/3] draft of the article done --- content/blog/serenity_why.md | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/content/blog/serenity_why.md b/content/blog/serenity_why.md index 41ff9c1..0d27550 100644 --- a/content/blog/serenity_why.md +++ b/content/blog/serenity_why.md @@ -1,8 +1,8 @@ --- -title: "" +title: "Serenity pains" -description: "" +description: "A rant against how serenity forces the developer to handle state" date: 2022-09-01 @@ -10,3 +10,28 @@ draft: true --- +This is the second blog article I've written dissing on how a library does something, the [first time](/blog/mineflayer_why) being effectively "Mineflayer doesn't do things the way I want it to and that annoys me". This article will probably follow in that tradition but unlike the Mineflayer one where I would've been inconvenienced to do what I want with Serenity I need to make my code potentially unsound to do what I want. + +## What is Serenity? + +[Serenity](https://crates.io/crates/serenity) is a rust crate that can be used to create discord bots. I've used it a couple of times without issue mainly for [DBMS](https://github.com/Pagwin-Fedora/DBMS) and [frame yeet](https://github.com/Pagwin-Fedora/discord-frame-yeet), very professional names I know. However the issues come up when you want mutable state in the [event handler](https://docs.rs/serenity/0.11.5/serenity/client/trait.EventHandler.html). + +## No mutable self + +For all the events in the event handler self is passed as a non-mutable reference. Which means you can't change any state in your event handler. Serenity... why? Have you not considered the possibility that someone may want to initialize something in their event handler after the bot has started or to have the response to events change due to previous events? + +## Yes they did consider the possibility + +It's why they pass a [Context](https://docs.rs/serenity/0.11.5/serenity/prelude/struct.Context.html) struct which has a field called data where data can be stored in a [TypeMap](https://docs.rs/serenity/0.11.5/serenity/prelude/struct.TypeMap.html) which mostly solves the inability to have mutable state. Keyword **mostly** + +## Drop the state + +The issue is what happens if the state being stored is attached to something else and you want the state to be dropped when that something else is dropped. Well in that case you just have to suffer in some way or another. You obviously need to implement the [Drop trait](https://doc.rust-lang.org/std/ops/trait.Drop.html) which means the struct needs to store a way to refer to the TypeMap in itself. But Serenity doesn't have a way to do that before you've constructed the client. The [ClientBuilder](https://docs.rs/serenity/0.11.5/serenity/client/struct.ClientBuilder.html) has the type\_map method if you want to provide one but that moves it which means you can't hold onto a reference to it that can be used in our Drop implementation. The ClientBuilder also has a get\_type\_map method which gives a reference to it's type map. But because it's a reference we can't give it to the thing that wants to potentially get rid of something in the TypeMap. Which leaves only ugly and uglier options for dealing with this. + +## Ugly solutions + +The first solution to this problem is to tell serenity to go fuck itself and write unsafe code convert self to a mutable pointer which we mutate in the ready event to initialize state within the handler with the Arc> that's provided by the Context struct. The second solution is to give up on having Drop clean up the TypeMap at the same time. Personally I think both of these solutions suck and wish that I wasn't forced to pick for the program I ran into this problem for. + +## Conclusion + +This is the only Serenity specific problem I've run into using this library though so I'd say it's a good library overall. So yeah, back to actually writing code instead of blog articles for now. From 166a2fef31109b6cc171ab4f4e2e570d3a89324b Mon Sep 17 00:00:00 2001 From: Pagwin Date: Tue, 6 Sep 2022 16:51:08 -0400 Subject: [PATCH 3/3] motherfucker I kept it draft --- content/blog/serenity_why.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/blog/serenity_why.md b/content/blog/serenity_why.md index 0d27550..f7d88c6 100644 --- a/content/blog/serenity_why.md +++ b/content/blog/serenity_why.md @@ -6,7 +6,7 @@ description: "A rant against how serenity forces the developer to handle state" date: 2022-09-01 -draft: true +draft: false ---