TypeFns, variadic generics, compile-time reflection, macro-like fns

Same concept, “functions” that are types and take types as arguments and put out types as outputs.

you may have noticed I talked about CTR and TypeFn separately? it’s because CTR is based on TypeFns - some TypeFns take a type and return supertraits, etc.

How would returning supertraits be represented in the type system? I am asking about returning traits,variadics aside.

Currently, statics leak out of macros and it’s possible for two macro invokations to conflict.

I want them to not conflict, unless you explicitly tell them to.

I want hygienic macros.

Think of a sealed box. Macro inputs are pipes into that box. But when you use static/etc, it’s like throwing a hammer at the box. There’s a good chance it’ll cause a leak. I want this to be fixed.

With a compiler built-in. As a type, rather than a fn/macro/whatever.

Symbols don’t appear out past the module boundary unless you given them the blessing to do so, and even then, they must be explicitly imported to be used outside. And it should be easy enough for anyone to create their own fresh non-conflicting identifiers and pass them into the macro to be used for only the static. Don’t see what’s so hard about asking for a unique symbol from the user for the macro.

If you need even more wrapping from the outside, you can declare inner modules, macro-generated or otherwise.

Returning a list of traits would look like this then?: types![ dyn Debug,dyn Display ]

Then,assuming we get reflection for getting supertraits, you could ask if the supertraits are exactly Display and Debug by doing this: Self:SuperTraits<Output=types![ dyn Debug,dyn Display ]>

types being a macro for producing a list of types.

but, in my code, I want to inspect and use supertraits at compile-time.

compare eventbus (my crate) semantics, with minecraftforge event bus (inspiration) semantics. they’re currently very different and I’d like to bring them closer.

I can’t help you with the type tricks you want to pull off, but as for some way of getting even more collision resistance of identifiers here’s a demonstration of creation of modules in macros, which allows for most of the heightened privacy you want in your macros:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=49f4f543f57d89c6c4946c9bc9fb8721

I am looking at this page and I can’t see anything that would require listing traits instead of listing types/trait impls when translated to Rust.

I would be in favor of adding reflection to Rust such that one can list the types that satisfy a particular constraint,using either a hlist encoding (List<value0,List<value2,Nil>>) or with variadics.

You may want to take a look at sub-events on that same page. They’re the exact thing I’m trying to simulate using (super)traits.

Assuming reflection exists,it sounds like it could be implemented with a SuperEvent associated type with a value of Some_<ListOfEvents>/None_

Edit: Here is an example of what a simple event trait could be :

struct None_;
struct Some_<T>(PhantomData<T>);

trait Event<AnEvent>{
    type SuperEvent;

    fn notify(&mut self,event:AnEvent);
}


struct Something{
    number:u32,
}

impl Event<u32> for Something{
    type SuperEvent=None_;

    fn notify(&mut self,event:u32){
        self.number+=event;
    }
}


struct OtherThing{
    number:u64,
}

impl Event<u64> for Otherthing{
    type SuperEvent=Some_<SomeThing>;

    fn notify(&mut self,event:u64){
        self.number+=event;
    }
}
let myevent = MyEvent(0);
post!(bus, dyn Event, dyn MyEventsPurpose, MyEvent, &mut myevent); // too error-prone, you could forget a supertrait or another.

I don’t believe your solution works anything like this but allows omitting the types?

You should try actually using the Forge bus, and then actually using my eventbus, rather than working based on assumptions.

And maybe you could explain what your constraints are and what you’re trying to achieve rather than expecting others to figure it out.

You know better than anyone else what you want. If you don’t explain it, there’s always going to be a difference between your view of the problem and others’ understanding.

Also, trying to translate Java patterns straight into Rust is a recipe for making your API look foreign to Rust users, and feel subtly off for Java users, if not worse.

From what I can read of the Forge docs, you might have better success creating an idiomatic Rust API with Futures, handles to these futures, and a dispatcher that will poll the ones registered for a particular event when it happens. Rust Futures don’t make progress unless polled, which may seem like a burden, but allow for a future to be abruptly cancelled if desired simply by dropping it from the futures to be polled the next time around.

6 Likes

I’ve used futures before.

My experience? Run. Abandon project immediately.

They exist in other languages, and I avoid them there too.

There’s nothing wrong or unidiomatic about events, except that I’m trying to get the most performance out of them.

Why events instead of futures?Async-await is going to be a thing long before trait reflection(assuming trait reflection is essential to events).

async-await is awful. if they were stackful coroutines I’d happily use them, but async-await, no.

and you can always convert events into async-await if you really want to. I’d much rather go the other way around, tho.

I can do this fine without compile-time reflection, it’s just a little more verbose.

I do want macro fns for more things than just eventbus, tho. they can do a lot for high-performance stuff.

How does what you are creating solve that problem?

events are neither async-await, nor stackful coroutines.

events are events.

I fail to see how they are better than async-await then.

Edit:Your comments don’t tell me anything about why you prefer this event system to async-await .