-
Notifications
You must be signed in to change notification settings - Fork 158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Evaluate whether or not counter-related macros can be renamed/simplified. #369
Comments
Here's a working proposal to get discussion started. Please "Tools -> Expand macros" and inspect. We make use of The proposal I'm making is that we replace fn main() {
// Comments are removed during macro expansion so we're just delimiting with `struct` here
counter!("foo", +, 1);
counter!("bar", =, 3);
counter!(level: Level::DEBUG, "baz", +, 1);
counter!(target: "custom target", "baz", =, 1);
counter!(target: "custom target", level: Level::TRACE, "baz", =, 1);
counter!("foo", +, 1, ("bar1", "baz1"), ("bar2", "baz2"));
counter!("foo", +, 1, "bar", "foo");
let counter: Arc<dyn CounterFn> = counter!("foo");
let counter: Arc<dyn CounterFn> = counter!("foo", ("bar", "baz"));
} Any assertion below should be prefixed with "as far as I can tell". An API such as counter!("name" += 1); counter!("name" = 1); is not possible because Having label key/value pairs grouped into a tuple means we can use |
I think it's important that others post APIs they'd like here and we can compare the merits. I'd like to set up a boundary between the feasible and unfeasible APIs. If you are unable to get a Rust playground proof-of-concept working I think it's still valuable to post and describe why you found it difficult. Maybe someone else will be able to make it work. |
One of the problems with this design, imo, is that counter!("name", +, 1, labels: ["key_a", "key_b"]) or even counter!(labels: ["key_a", "key_b"], "name", +, 1) |
Another route here is that we simply don't have any macro arguments for counter!("name").set(value);
counter!("name").add(value); The more I think about it the more I'm in favor of this approach. If we go down this path perhaps we should make the |
At first blush, I viscerally dislike the variant with the operation sigil (+, -, etc) as one of the macro arguments. 😂 An interesting thought, but too clever by half in practice, I'd imagine. That said, the overarching theme of "can we use one macro to do more than one operation?" is a good theme. The idea around pushing towards directly calling methods for the relevant operation (i.e. |
Just talking out loud.... the pros/cons for the "use methods instead of individual operation macros": Pros
Cons
|
Here's the proof-of-concept using just methods on A nicety that could become standard practice if we adopted the "use methods" approach: If impl AddAssign<u64> for Counter {
fn add_assign(&mut self, value: u64) {
self.increment(value);
}
} we can counter!("name") += 1; Similarly, for |
This is a massive pro in my opinion—discovering what a macro can and cannot do is an exercise in careful examination of the docs, while methods combine super-nicely with in-editor auto-completion. They are also very searchable in the auto-generated API reference. |
An idea on this topic: if the macro returned a type that was marked as |
I agree that I'm guessing the implementation looks something like this? #[must_use]
struct CounterGuard<'a> { recorder: &'a Recorder, metadata: &'a Metadata, key: &'a Key }
impl CounterGaurd {
fn register(&self) -> Counter { self.recorder.counter(self.metadata, self.key) }
fn add(&self, value: u64) { self.register().add(value) }
}
let guard: CounterGuard = counter!("name"); |
I'm happy to draft out a PR for this when a direction is decided on #369 (comment). I think this makes sense: counter!(target: "target", level: Level::DEBUG, labels: [foo, bar, baz], "name")
counter!(target: "target", level: Level::DEBUG, labels: [(foo_key, foo_value), (bar_key, bar_value)], "name") |
I think my biggest question is: why the switch from |
Not a particularly strong argument and just writing this out has kinda convinced me that the existing label syntax is fine but: at the moment we accept let dyn_vals = [(dyn_key_a, dyn_val_a), (dyn_key_b, dyn_key_b)];
counter!(&dyn_vals);
counter!(dyn_key_a => dyn_val_a, dyn_key_b => dyn_val_b);
counter!(dyn_pair_a, dyn_pair_b);
counter!("static_key_a" => "static_val_a", "static_key_b" => "static_val_b"); it feels a little more consistent if let dyn_vals = [(dyn_key_a, dyn_val_a), (dyn_key_b, dyn_key_b)];
counter!(&dyn_vals);
counter!((dyn_key_a, dyn_val_a), (dyn_key_b, dyn_val_b));
counter!(dyn_pair_a, dyn_pair_b);
counter!(("static_key_a", "static_val_a"), ("static_key_b", "static_val_b")); It does look like it adds some noise though. Another alternative to counter!(dyn_key_a = dyn_val_a, dyn_key_b = dyn_val_b);
counter!(dyn_pair_a, dyn_pair_b);
counter!("static_key_a" = "static_val_a", "static_key_b" = "static_val_b"); or even counter!(dyn_key_a: dyn_val_a, dyn_key_b: dyn_val_b);
counter!(dyn_pair_a, dyn_pair_b);
counter!("static_key_a": "static_val_a", "static_key_b": "static_val_b"); Both I guess
I applied this to labels too, but on further consideration, if labels are going to be the last of the arguments then it doesn't really help using |
Yeah, I realize that there's an asymmetry to what is technically accepted due to allowing both the key/value notation and expressions... but in my mind the difference is that the fact tuples are accept is a consequence of allowing expressions, not the macros inherently destructuring the actual tuple notation. My thought is that if it's not much harder/complex to keep |
I think we agree enough now and we can argue about the details in the PR. Will get it written up soon. |
Are we happy with the state we've landed in now that #394 is merged? |
I would say that, yeah, this issue has been resolved with the merging of #394. 👍🏻 |
As mentioned in #338, it can be confusing when trying to figure out which counter macro to use for a given scenario, as we have
counter!
,increment_counter!
, andabsolute_counter!
.We should consider if there's any potential simplification we could apply. One form this proposed simplification could take is around exploring if one macro could serve both the "increment by N" and "increment by 1" use cases, rather than having them be distinct macros.
The text was updated successfully, but these errors were encountered: