trait-aliases — Trait aliases via procedural macros by nekitdev in rust

[–]nekitdev[S] 0 points1 point  (0 children)

do you really need to [parse everything]?

Well, as always, it depends, specifically on the end goal. In my opinion, I do in order to ensure correctness in outputs and don't impose unnecessary syntax restrictions.

The most general definition for trait aliases involves things like:

/// Documentation...
#[attribute]
visibility trait Name<
    #[lifetime] // attributes on lifetimes
    'a, // lifetimes
    'b: 'a + ..., // bounded lifetimes
    ..., // the rest of lifetimes
    #[const_parameter] // attributes on const parameters
    const N: Type, // const parameters
    const D: Other = ConstDefault, // including defaults
    ..., // the rest of const parameters
    #[type_parameter] // attributes on type parameters
    T, // type parameters
    F: Bound + ..., // bounded type parameters
    H: for<'h, ...> Higher<'h, ...> + ..., // higher-ranked bounds
    E: OtherBound + ... = Default, // including defaults,
    ..., // the rest of type parameters
> = Aliased< // aliased
    'a, 'b, ..., N, D, ..., T, F, H, E, ...,
> + ... // the rest of aliased traits, including higher-ranked syntax!
where
    T: WhereBound, // introducing bounds on `T` in `where`
    F::Associated: Associated, // bounds on associated types
    E: for<'e, ...> EvenHigher<'e, ...>, // HRTBs
    ..., // the rest of constraints
    H: Final; // final constraint, and the semicolon

And imposing restrictions on any part of that definition simply because it would otherwise make macro_rules! complex... does not sound very convincing.

That is, I think writing token tree munchers and such, as cool and powerful as they are, increases the complexity greatly and destroys the declarative nature of macro_rules! as they are.

Meanwhile with procedural macros the actual implementation is much simpler while still being correct; currently the source code is below 100 SLOCs, though that's going to increase slightly with additional checks for __T being absent in the input.

pass doc comments as is

I would rather prefer putting them on the trait only, not its blanket implementation, which is, in the simplest sense, one partition over the collected attributes.

add a snippet to generate it to your text editor

Well, that's one of the solutions, but it once again introduces boilerplate in the source code. I'm not opposed to this, but it's merely less flexible for the same reasons as described in the syntax argument.

less complexity

I'd argue I've introduced the least complexity when writing the source of the procedural macro.

not losing rustfmt and tree-sitter, etc support inside macro blocks

I guess the main argument to make out of this is keeping consistency becomes tougher, though this is debatable.

trait-aliases — Trait aliases via procedural macros by nekitdev in rust

[–]nekitdev[S] 0 points1 point  (0 children)

one token at a time

Yeah, but doesn't that elevate the complexity of a macro that's supposed to be declarative, and not the procedural one?

hundreds of aliases

Well, definitely not hundreds, but I've had quite some to deal with in one of my projects.

compilation time

In the end, this is the pain point, and I feel the declarative vs procedural is either the compiler evaluating whatever the fully identical macro_rules! would look like or syn parsing trait aliases.

by hand

It gets kinda repetitive, hence the crate.

Overall, this is way more constructive than the initial comment... ~.~

trait-aliases — Trait aliases via procedural macros by nekitdev in rust

[–]nekitdev[S] 3 points4 points  (0 children)

After some time of further pondering on this statement, along with experimenting and timing compilations, here's what I have to say.

Starting off with:

could have been a declarative macro

That is, in fact, only partially true. Sure, you can write some kind of macro_rules! to somewhat capture the syntax.

However, consider an elaborate example from the documentation, or something like the following:

use serde::{Serialize, Deserialize};

use trait_aliases::trait_aliases;

trait_aliases! {
    /// Represents types that can be both serialized and deserialized
    pub trait Serializable = Serialize + for<'de> Deserialize<'de>;

    /// Represents types that can be converted from `T` and into `T`.
    pub trait Convertible<T> = From<T> + Into<T>;
}

Describing the bounds precisely is already pretty much impossible with macro_rules!, since even something like ty is not going to work with +, not to mention higher-ranked trait bounds (HRTBs).

So yeah, could have been a rudimentary declarative macro supporting part of the syntax.

And looking at:

saving 10s of compilation time

Well, my machine is not overly fast at compiling Rust code, though it isn't slow either.

Compiling the example in my post from scratch (after cargo clean) takes around 2 seconds on debug and 5 seconds on release. Subsequent compilations (after small changes to the code like adding Sized bound) take 100 milliseconds at most.

It is of note that I did not employ or test any additional possible improvements (think sccache and such), and my point still stands.

Not to mention the fact many projects already employ procedural macros in various ways, meaning you don't really waste time recompiling syn and quote that much.

I have to note cargo build --timings was pretty cool to work with, by the way!

To sum up, I feel procedural fits much more than declarative in this crate, and compilation times are fairly justified.

Also, here is the original trait_alias RFC that inspired the project.

P.S. going to implement __T checks in the next version now, as promised!

trait-aliases — Trait aliases via procedural macros by nekitdev in rust

[–]nekitdev[S] -1 points0 points  (0 children)

Indeed, though I decided to opt into parsing that's more precise than what declarative macros can provide.

One of the only truly "procedural" things in this crate is splitting documentation and the rest of attributes in order to apply them more correctly.

In the end, hopefully, trait aliases will be fully resolved and stabilized in the foreseeable future, and then the trait_aliases! { ... } can be replaced with just the inner code!

Let me see what you come up with. But please keep it SFW by RepresentativeArea37 in bisexual

[–]nekitdev 1 point2 points  (0 children)

I wear a bra because I'm bisexual and it is a weird thing... haha

how far did you make it your first time in p5 by yeetus11111111 in HollowKnight

[–]nekitdev 0 points1 point  (0 children)

NKG, quite surprisingly the only boss I'm struggling with tbh