Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 days ago.
Improve this question
For our codebase, we have quite a few asynchronous calls which require the async await flow since we make a lot of API calls. However, in some of these classes, we use some functions which, in nature, do not require any async operations like if-else statements on a String, an example is given below.
static async isValidLength(name){
if (name.length() > 5){
return true;
} else {
return false;
}
}
I want to argue since we mostly use async operations, wrapping all functions in an async await flow is more maintainable and less error-prone to forget using await in some truly async operations, which can cause the programme to behave in unexpected ways.
I tried to search the web whether there were some recommended conventions around this but I couldn't really find anything, so I'm asking for experiences/opinions on the matter here. Is it a bad practice to wrap non-async functions with the async keyword?
This would make your code a mess. Imagine if you wanted to reverse each word in a string, and the split(), reverse(), map(), and join() functions were all async. It would look something like this:
const reversedWords = await (await Promise.all((await str.split(' ')).map(w => w.reverse())).reverse()).join(' '));
I could stare at that for 15 minutes and still not know if I did it right (probably didn't).
Every function call will have the overhead of wrapping the result in a promise.
And you'll make the problem you're trying to solve even worse. Developers will have to put await on every single line of code they write. If they forget that anywhere: bug.
Consider using ESLint rules instead. Or simply test the code.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
My use case:
I have a large complex struct.
I want to take a snapshot of this struct to send it to a thread to do some calculation.
Many large fields within this struct are not neccessary for calculation.
Many fields within the struct are partially required (a field may be a struct and only a few parameters from this struct are required).
At the moment I simply call .clone() and pass a clone of the entire struct to the thread.
It is difficult to give a good example, but this is a summary of my current method:
use tokio::task;
fn main() {
let compex_struct = ComplexStruct::new(...);
// some extra async stuff I don't think is 100% neccessary to this question
let future = async_function(compex_struct.clone()); // Ideally not cloning whole struct
// some extra async stuff I don't think is 100% neccessary to this question
}
fn async_function(complex_struct:ComplexStruct) -> task::JoinHandle<_> {
task::spawn_blocking(move || {
// bunch of work, then return something
})
}
My current working idea is to have a seperate struct such as ThreadData which is instantiated with ThreadData::new(ComplexStruct) and effectively clones the required fields. I then pass ThreadData to the thread instead.
What is the best solution to this problem?
I think you've answered your own question. 😁 If you're just looking for validation, I believe a refactor to only the needed parts is a good idea. You may find ways to simplify your code, but the performance boost seems to be your reasoning. We can't see benchmarks on this, but perhaps you want to track that.
This part is just my opinion, but instead of ThreadData::new(), you could do ThreadData::from(), or better yet, impl From<ComplexStruct> for ThreadData {}. If it only has one purpose then it doesn't matter, but if ThreadData will ever be used in a different context, I like to keep the "new"/"from" functions available for a general instance. Otherwise I eventually have Struct::from_this(), Struct::from_that(), or Struct::from_some_random_input(). 😋
This question already has answers here:
How do I synchronously return a value calculated in an asynchronous Future?
(3 answers)
Closed 2 years ago.
Rust newbie here (<7 days into learning), the second hurdle I am trying to overcome after ownership rule is async/await.
I am writing a test that calls an async function and I need to get the result from the Future without using the keyword await.
I have looked at async_test, however I can't use that because (as I understand) this requires tokio runtime and #[tokio_main] attribute in my main method - but I have my main already decorated with #[actix_rt::main]
This is my test
#[test]
pub fn test_get_item() -> Result<(), anyhow::Error> {
let c = SomeClient::new();
let result = c.get_item(123456).await?; // <- this is not allowed
assert_eq!("Hello", result.title);
assert_eq!("https://example.com", result.url.as_str());
Ok(())
}
Things I have tried and failed (mostly due to my lack of knowledge in Rust)
Use async_test on an actix web project using futures-await-test crate.
Read this thread in reddit.
Follow few examples from this rust community thread
Tried to poll() the future but it didn't lead me anywhere.
I don't understand why this has to be so complicated, maybe there is a simple function (like wait() or get_result()) somewhere for Future?
Thanks for your help.
Had to clear my head for a bit and start again, just to find actix-web has a macro I can use that allows async tests.
#[actix_rt::test]
Macros are all magic to me at this point, I hope I;ll understand them soon.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
In a blog post, Rust contributor withoutboats mentions:
Most of my functions with many return paths terminate with a match statement. Technically, these could be reduced to a single return path by just wrapping the whole match in an Ok, but I don’t know anyone who considers that good form, and I certainly don’t.
A (somewhat contrived) example of this--
bad:
Ok(match response {
UserResponse(user) => user,
ItemResponse(item) => item?,
})
better:
match response {
UserResponse(user) => Ok(user),
ItemResponse(item) => Ok(item?),
}
Why is that the case?
This is kind of a tricky question to answer. I personally can't recall ever seeing anyone express this opinion before. To be fair, I can't say that I've ever heard the opposite. That is, I don't remember anyone ever explicitly encouraging this sort of pattern in code.
I've certainly used this pattern before, although somewhat sparingly. To demonstrate, this typically occurs when you have a match expression with several cases in a tail expression that returns a Result, and you don't want to write Ok for each case. Like this:
Ok(match something {
Something::Foo => 1,
Something::Bar => 2,
Something::Quux => fallible?,
Something::Baz => return Err(...),
})
As opposed to
match something {
Something::Foo => Ok(1),
Something::Bar => Ok(2),
Something::Quux => fallible,
Something::Baz => Err(...),
}
It's not a huge difference, but if you have a lot of Ok cases, it can get a bit annoying. Or at least, this was the primary complaint in Boat's blog post (in defense of Ok-wrapping).
Another variant of this pattern is 1) when your function returns a Result, 2) the tail expression of the function is also a Result, 3) the error types are not the same and 4) the error type in (1) has a From impl for the error type in (2). That is, instead of writing
something.fallible().map_err(From::from)
one can write
Ok(something.fallible()?)
? is so ubiquitous that I've always kind of chalked up the difference between these to personal style.
I can't possibly know what the blog author had in mind when saying that this was poor form. My guess---and I somewhat share this---is that there is a lack of symmetry between the arms of the match expression. Some of them are effectively early returns while others aren't early returns at all. I could see how some might consider that jarring.
Otherwise, I do occasionally use both of these patterns, but not religiously so. If it comes up and it makes sense, then I don't have too much of a problem with it.
Imagine you are creating a framework for nodejs.
Is there any good practices to handle sync/async code.
I'm talking about the sync-to-async problem as follows:
All over your libraries you have code that from the beginning is sync for example:
function validate(email) {
return email.match(/regex-blah/)
}
When you need some IO async operation inside the functions they should become async (with async keyword or promises). Doesnt matter.
async function validate(email){
...
}
What matters is that all callers (called "x") to "validate" should become async also - and all callers to "x"
Which becomes very hard to support and maintain.
This could be a problem in a client side framework also i think.
Is there any good rules to avoid that problem.
Thanks
So I've recently hopped on the async/await train, well attempting to I'm still grasping some concepts.
I've started by switching as much as I can to async/await and the packages that don't offer it yet I found promise versions.
Anyways, I stumbled upon the request-promise-native module which is just like request but utilizes promises as I'm sure you can see.
I've been experimenting with using async/await with it and it works but I'm not sure I'm using it right. In fact I'm not even sure if it has advantages over using the promise but this particular function I'm converting has a lot of callbacks so I'm trying to keep the amount of tabs at a minimum.
testFunction: async (param) => {
let results;
try {
results = await request(requestOptions);
} catch (e) {
return (e);
}
// Do stuff with results
Now this works and I get the desired result but my question is 1. Is this even the right way to use async/await and 2. Is there any benefit to this over the standard promise offered by the library?
You are indeed using async/await correctly. The function definition must be preceded by async exactly like you've done, and the await operator should precede the code that returns the Promise, exactly like you've done. It is also correct to wrap await in a try/catch because if the Promise is rejected, the await expression will throw the rejected value (see MDN).
The benefit is code that appears synchronous, which makes it easier to follow, understand, and reason about.