I use java a lot and I am familiar with AOP usage in java. Recently I am learnig rust. Rust is a AOT compile language, so it is not easy to do some AOP thing like java. Although I find some rust crates about AOP, they are not popular. AOP is a good ability to make programmer design scalable system, is rust support the ability well and we need AOP in rust?
You're not going to get completely source transparent join points outside of abusing low level profiling tools - its simply too much against the design of the language.
But not all is lost, tracing provides extremely low source overhead logging and diagnostic support with the #[instrument]
annotation, the example always given for AOP.
For other uses, traits provide a great way to add functionality to types you don't own, macros can be used to apply nearly arbitrary transformations at build time to your own code (a simple example being wrapping with access control code), and build scripts letting you run arbitrary code every build which could probably be used for many of the tougher examples.
If you have specific cross cutting concerns there's probably already a crate, and feel free to ask here how that issue would be approached by a rustacean!
For context, I am the author of "AspectJ in Action".
Agree with @simonbuchan. The meta-programming offered by macros can take care of several AOP use cases (especially if you would have needed annotation to select join points, anyway).
In other cases, the availability of higher-order functions can help. For example, if you need to monitor the time taken by a block code, you could write:
fn monitored<T, F>(f: F) -> T
where
F: FnOnce() -> T,
{
let start = std::time::Instant::now();
let result = f();
let elapsed = start.elapsed();
println!("elapsed: {:?}", elapsed); // Or use the tracing library here
result
}
And then use it like:
monitored(|| print!("hello"));
monitored(|| {
for _ in 0..10 {
// perform some work
}
});
All these cases, however, require some intervention at the point of action (an annotation, calling a higher-order function). So for example, you wouldn't be able to monitor all implementations of a particular trait, unless you change all those implementations. In such cases, an AOP implementation could help. However, Rust's stress on explicitness goes against AOP, so I do not see AOP in Rust anytime soon.
The AOT part of Rust shouldn't pose a problem in implementing AOP in Rust. Like AspectJ, an imaginary AspectRust compiler could weave in code for dynamic (runtime behavior changes) and static crosscutting (structural changes) at compile time.
@simonbuchan @ramnivas Thanks for your reply which help me a lot. Let me try to give a conclusion about the topic:
- Rust's design concept is explicitness so the native rust not give any infra to do the AOP things.
- We can use the following solutions to do the most AOP things:
- work with #[instrument] : use crate like tracing supported with #[instrument]
- use traits to add functionality
- use high-order function
- use macros
It's quite common to use thread locals to pass some context implicitly through the call stack. Check out the scoped-tls
crate which helps a lot to build such system.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.