Replies: 6 comments
-
We use heap allocated strings because a lot of the events are received as well as sent, so the String either A. has to last as long as it's received event or B. has to be heap allocated. |
Beta Was this translation helpful? Give feedback.
-
Ah, that's the cool thing about |
Beta Was this translation helpful? Give feedback.
-
According to
|
Beta Was this translation helpful? Give feedback.
-
Why 32 bytes?That is true. Please correct me if I'm wrong, but I presume that the extra bits come from the fact that Why is this not an issue?A core assumption I am making here is that most usage of Arguably, this has greater implications for memory than the A concrete exampleConsider a situation where we have a string with 10 or so ASCII characters (for the sake of argument). With Now, this is not the case for But in case we do need dynamic allocation, |
Beta Was this translation helpful? Give feedback.
-
This could be useful for things such as Embed, or data we send to discord, however models such as |
Beta Was this translation helpful? Give feedback.
-
I agree. 👍 Though, it does come with the downside that the API becomes less consistent with strings. I'm not sure how you feel about that from a UX perspective. Personally, I can live with it, but some may argue that we may as well go all-or-nothing here. |
Beta Was this translation helpful? Give feedback.
-
Currently, most string fields in the
twilight-model
crate take in an ownedString
. This is fine, but I realize that for most cases, a plain&'static str
is sufficient. The mandatory heap allocation (from theString
) is thus usually unnecessary. Consider this example with rich embeds (using0.10.2
):Hopefully, it is apparent from my example that there are too many
String
allocations here, where plain&'static str
slices will suffice. We can also note theVec
allocation, which is arguably unnecessary since we know for certain that there is only one element.1Of course, this example also applies to other areas of the library. Rich embeds are just one particular instance.
A Possible Solution
In line with the goal to reduce heap allocations, I propose that we consider using the
alloc::borrow::Cow
smart pointer instead ofString
andVec
. TheCow
smart pointer employs "copy-on-write" semantics so that heap allocations are kept at a minimum.Now, I understand that ownership is one of the primary reasons why
String
andVec
were chosen. After all, it becomes rather cumbersome to use many of the data models if explicit lifetimes were required—though, I personally wouldn't be totally against this proposition.Anyway, a good compromise is to use a
Cow<'static, str>
and aCow<'static, [T]>
(for all typesT
). Observe that the'static
lifetime specifier enforces that the data model (practically) "owns" the slice, even though it is technically borrowed. Therefore, the enclosingstruct
need not be generic over arbitrary lifetimes.This gives the user extra flexibility on whether to use a
&'static str
or a regularString
(e.g. in cases where string interpolation is necessary). Consider the same rich embed example from earlier:It is important to note that there are now zero allocations here. Both the
Vec
andString
have been removed in favor of their'static
counterparts. In case string interpolation or dynamic arrays are needed, one may useCow::Owned
variant instead (containing the appropriateString
orVec
). Consider this other example for mixed usage:Suggestions for Migration
Most builder setters and utilities from this library rely on the fact that the intended target field is a
String
or aVec
. I'm aware that it will be rather tedious to convert all of the parameters to theirCow
-equivalent. Luckily, generics come to the rescue! Suppose we intend to migrate to theCow
smart pointer for the builders in thetwilight-util
crate:The standard library already provides the convenience
From
andInto
implementations. From the user's perspective, constructing anEmbedFieldBuilder
still works the same as before thanks to the standard conversions.Footnotes
In addition to the heap allocation, extra copies of the data also occur due to the fact that the
String::from
implementation simply copies the bytes from the&'static str
into the new allocation. TheVec
works in a similar fashion. ↩Beta Was this translation helpful? Give feedback.
All reactions