# Associated Statics - a way to have high performance, (mostly) statically dispatched event busses

**URL:** <https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901>\
**Category:** language design\
**Created:** [March 4, 2018, 7:53pm UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901 "2018-03-04T19:53:02Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [March 4, 2018, 7:53pm UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/1 "2018-03-04T19:53:02Z")

</div>

I recently decided to look back on an event bus I wrote a long time ago. I had to do things like this back then:

```rust
/* some things omitted for simplicity */

pub trait Event {
  fn use_internal_data<F, T>(f: F) -> T where F: Fn(&InternalData<Self>) -> T;
  fn use_internal_data_mut<F, T>(f: F) -> T where F: Fn(&mut InternalData<Self>) -> T;
}

pub struct EventMetadata<T: Event> {
  handlers: Vec<EventHandlers<T>>,
}

impl<T: Event> EventMetadata<T> {
  pub fn new() -> EventMetadata<T> {
    EventMetadata { handlers: vec![] }
  }
  fn get_or_create_handlers(&mut self, bus: EventBus) -> &mut EventHandlers<T> {
    self.handlers.get(bus.id()) /* also some logic to grow the vec and stuff */
  }
}

```

(Yes, I now realize use\_internal\_data\_mut can be exploited to set/replace the InternalData.)

The way this works is that you’d create a static EventMetadata (using lazy\_static) for every impl you make, and pass it on as needed in places where it’s relevant. The goal is to provide (as close to) static dispatch (as possible) - with the EventBus code mostly just calling the EventMetadata functions, all usages of the Event basically boil down to getting the bus ID, and getting the vec entry for it. This is much faster than doing some unnecessary hash operations (which you would have to do if you were using, say, AnyMap).

However it would be nice to be able to do it like this instead:

```rust
pub trait Event {
  static INTERNAL: private::EventMetadata<Self> = /* something here, perhaps something with lazy initialization */;
}

mod private {
  pub struct EventMetadata<T: Event> {...}
}

```

And then the user doesn’t need to provide EventMetadata themselves (or be able to look at it), which can avoid quite a lot of confusion (as some might think EventMetadata lets you associate additional data to an event _instance_, while it’s metadata about the event _type_). This also simplifies the monomorphization case (as monomorphization can generate a static for every monomorph), so if you had a `VecEvent<T>(Vec<T>)` for example you wouldn’t need to impl a separate `Event` for every `VecEvent<T>` you wanna use. (or you might not be able to, if the `VecEvent<T>` is from another crate!)

The reason you can implement the Event trait even tho you can’t `use eventbus::private::EventMetadata` is because when using the default value the impl can be omitted. So you don’t ever reference the `INTERNAL` static in your trait impl, thus not having to reference its type either.

---

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [March 5, 2018, 12:35pm UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/2 "2018-03-05T12:35:33Z")

</div>

For context, I’m trying to avoid things like this:

[https://mozilla.logbot.info/rust/20180303#c14394317](https://mozilla.logbot.info/rust/20180303#c14394317)  
[https://mozilla.logbot.info/rust/20180303#c14395430](https://mozilla.logbot.info/rust/20180303#c14395430)  
more importantly, this kind of confusion: [https://mozilla.logbot.info/rust/20180303#c14395745](https://mozilla.logbot.info/rust/20180303#c14395745) (cont [https://mozilla.logbot.info/rust/20180303#c14395821](https://mozilla.logbot.info/rust/20180303#c14395821) and [https://mozilla.logbot.info/rust/20180303#c14395901](https://mozilla.logbot.info/rust/20180303#c14395901) )

---

<div class="post-metadata">

**Author:** ![nikomatsakis](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nikomatsakis/32/5410_2.png) [@nikomatsakis](https://internals.rust-lang.org/u/nikomatsakis)\
**Post date:** [March 6, 2018, 12:10am UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/3 "2018-03-06T00:10:37Z")

</div>

It seems like we could support associated statics readily enough. (And, equivalently, generic statics and constants.)

---

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [October 2, 2018, 11:02am UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/4 "2018-10-02T11:02:49Z")

</div>

I’ve been told this doesn’t work with dynamic linker very well, but I’d really like this to be possible. it’d be very useful.

---

<div class="post-metadata">

**Author:** ![oooutlk](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/oooutlk/32/4627_2.png) [@oooutlk](https://internals.rust-lang.org/u/oooutlk)\
**Post date:** [October 2, 2018, 2:14pm UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/5 "2018-10-02T14:14:45Z")

</div>

> [@Soni](#):
>
> I’ve been told this doesn’t work with dynamic linker very well, but I’d really like this to be possible. it’d be very useful.

I guess you meant [here](https://internals.rust-lang.org/t/how-about-generic-global-variables/8351/8)

---

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [October 2, 2018, 4:00pm UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/6 "2018-10-02T16:00:13Z")

</div>

yep. maybe we should consider getting our own dynamic linker!

---

<div class="post-metadata">

**Author:** ![comex](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/comex/32/2587_2.png) [@comex](https://internals.rust-lang.org/u/comex)\
**Post date:** [October 3, 2018, 1:21am UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/7 "2018-10-03T01:21:34Z")

</div>

Not that this helps, but it works pretty much everywhere except for Windows.

---

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [October 3, 2018, 1:41am UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/8 "2018-10-03T01:41:05Z")

</div>

is it possible to implement a workaround on windows?

a bootstrap dynamic linker bundled with the rust-based dll that then loads a rust dynamic linker to fix up the dynamic linker?

---

<div class="post-metadata">

**Author:** ![gnzlbg](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gnzlbg/32/3858_2.png) [@gnzlbg](https://internals.rust-lang.org/u/gnzlbg)\
**Post date:** [October 5, 2018, 1:31pm UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/9 "2018-10-05T13:31:11Z")

</div>

I find it super-confusing, non-intuitive, and annoying, that associated items are not available for all kinds of types.

For example, one can add associated consts to both traits and structs, but one cannot add associated types to structs.

For consistency, associated statics should be usable for `enum`s, `struct`s, tuple `struct`s, `union`s, etc. as well, not only traits, so that I can write:

```rust
struct A;

impl A {
    static FOO: X = Y;
}

```

I wish the whole associated items stuff would receive some consistency love before making it more complicated with GATs, associated statics, etc.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [October 5, 2018, 7:33pm UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/10 "2018-10-05T19:33:34Z")

</div>

> [@gnzlbg](#):
>
> but one cannot add associated types to structs.

This is due to technical challenges (awaiting lazy normalization) but it will happen eventually and it has been accepted by an RFC.

As for associated statics, if you can ensure that each static when monomorphized at a certain type has a single memory address, then I have no objections to adding it for consistency. But you will need to write an RFC to plug that consistency hole.

---

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [October 21, 2018, 9:29pm UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/11 "2018-10-21T21:29:56Z")

</div>

I think I’ve figured something out here:

[https://cybre.tech/SoniEx2/rust.eventbus/src/branch/master/src/lib.rs#L113-L158](https://cybre.tech/SoniEx2/rust.eventbus/src/branch/master/src/lib.rs#L113-L158)

this is _painful_ but I think something like this could work? even on windows?

basically, as part of monomorphization, we generate something similar to this. except the compiler would be able to heavily optimize it:

- the compiler can coalesce all occurrences of the same generic static into a single `static ID: AtomicUsize`/`static ID_INIT: Once` pair. this is way more efficient than these macros.
- (for best results) these “ID” statics would be part of the monomorphized functions, not of the caller. (if not possible, might require small tweaks to ABI calling conventions)
- calling it isn’t an ugly PITA, and you’d actually be able to see where the busses etc are being used. compare:

```rust
let mut event = foo;
register_hook!(&bus, 0, MyEvent, |event| foo);
post_event!(&bus, MyEvent, &mut event);
// vs
let mut event = foo;
bus.register_hook(0, |event: &mut MyEvent| foo); // type inference doesn't work here, heh
bus.post_event(&mut event);

```

the main thing here is the use of `bus.whatever` instead of macros. it’s almost like `bus.` acts as a sort of “indentation” as far as the eyes are concerned, so it becomes a lot easier to read. (not sure how to describe this any better)

note that the existing requirements of static variables (namely that the contents must be 'static, Send and Sync) fit quite well with the requirements of Any.

---

<div class="post-metadata">

**Author:** ![retep998](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/retep998/32/729_2.png) [@retep998](https://internals.rust-lang.org/u/retep998)\
**Post date:** [October 31, 2018, 6:29pm UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/12 "2018-10-31T18:29:02Z")

</div>

The key issue with Windows is combining monomorphization with dylibs. If a generic symbol is monomorphized the same way in two dylibs, there is **no** way in the Windows linker model to deduplicate that when both dylibs are loaded in the same binary.

---

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [October 31, 2018, 6:37pm UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/13 "2018-10-31T18:37:26Z")

</div>

What if instead of implementing a costly solution, we just provide a workaround?

Let the libs figure it out, but help them do it.

See my other thread about static generics (in functions), etc? That would help.

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [October 31, 2018, 7:41pm UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/14 "2018-10-31T19:41:28Z")

</div>

@Soni I’ve read all of your other threads, but I didn’t see anything in them that makes a difference here. They seem to all be proposing different syntaxes for declaring generic statics (and some other stuff), but none of those threads even seemed to mention the fundamental problem that generic statics and dylibs are mutually exclusive, much less propose any sort of solution or workaround.

Do you have some sort of workaround in mind that you’ve been trying to propose but failing to articulate?

---

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [October 31, 2018, 9:01pm UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/15 "2018-10-31T21:01:22Z")

</div>

You have a shared dylib that works as a registry for the other dylibs. The other dylibs touch this registry and manipulate their statics to point into this registry. You then have what I call a “dynamic linker hack” - you tell the OS dynamic linker to load a dynamic linker of sorts that’s used exclusively by Rust, and use that instead.

---

<div class="post-metadata">

**Author:** ![Jingbee](https://avatars.discourse-cdn.com/v4/letter/j/65b543/32.png) [@Jingbee](https://internals.rust-lang.org/u/Jingbee)\
**Post date:** [December 21, 2018, 5:37pm UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/16 "2018-12-21T17:37:40Z")

</div>

I’m implementing a crate to add some kind of reflection to Rust, and associated statics would be very helpful. However I’m not clear about the semantics you propose here.

What if you implement the trait (containing a static field) for a type parameterized with lifetimes.

```
impl<'a> for A<'a> {
  static FOO : X = Y;
}

```

Does that mean that you would have one `X` instance for each possible lifetime ? This is how I would interpret the semantics… Unless you only consider the types after having the lifetimes removed ?

---

<div class="post-metadata">

**Author:** ![Soni](https://avatars.discourse-cdn.com/v4/letter/s/a3d4f5/32.png) [@Soni](https://internals.rust-lang.org/u/Soni)\
**Post date:** [December 21, 2018, 5:55pm UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/17 "2018-12-21T17:55:12Z")

</div>

Any static must have T: 'static. Associated/generic statics do so, too. Since any associated static can be desugared into a generic static, it requires the type to be 'static (for now, sadly).

This is assuming we don’t get any sort of HKTs. [See also](https://internals.rust-lang.org/t/better-handling-of-fn-mut-t-and-friends-for-improved-futures/9072).

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [March 25, 2019, 8:29am UTC](https://internals.rust-lang.org/t/associated-statics-a-way-to-have-high-performance-mostly-statically-dispatched-event-busses/6901/18 "2019-03-25T08:29:45Z")

</div>

Closed on March 25, 2019, 8:29am UTC

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
