Should I use async function in new function?

Should I use async function in new function to initialize a field (thus new would become async) or instead put that async initialization (with now an Option field initialized with None in new) in an individual async function that must be called later?

Thanks.

Is your thing useful when thing.field is None?

1 Like

Generally not…Do you mean the decision depends on this ? I wonder making whether new function async is a good practice or not. Or should I use block_on inside to avoid this. I always have the sense that only very lightweight operations should do in new function.

My understanding is that there is nothing special about any new() function one creates. Using the name "new" is just a convention. They are like any other function you write. Your new() function does not even need to be called "new". It is nothing like new in C++.

So the question as to whether your function called ´new` should be async or not is the same as question as for any other function you write.

3 Likes

Thanks for you reply. I know that it is associated function. I wonder if there are some conventions about this .

The convention is to never make fn init(&mut self) like functions in any form. This kind of functions make it impossible for the type system to track if the value is initialized. Means you can't get compile error on touching (logically) uninitialized value. Compared with it, having async on fn new() or not is trivial.

4 Likes

A prevalent convention is that the result of new is immediately usable and valid, and it'd certainly strike me as unnecessarily fragile if you had to call another separate method to get a usable object. If that means new has to be async then IMO there's no overriding reason not to - as ZiCog says, "new" is only a naming convention, the language doesn't care - but it also might be worth considering whether whatever data you need to fetch asynchronously can instead be passed to the constructor as a parameter so the rest of the function can be sync. This is likely to be more testable because, e.g. you can swap out the source of the value more easily

2 Likes

I always have a strong opinion against "two-phase-intialization" or "two-stage-construction", even in C++. (there's a cppcon lightning talk for those from C++ background).

the problem with two phase initialzation is that you have to add "partial constructed" states into your type (e.g. the Option type mentioned in the original post), which brings no benifits whatsoever, but makes the safety guarantee of your type weaker, because you can't hold certain invaraint in your type anymore, and you always need to check at runtime.

a constructor is where you should establish the invariants of your type, if the object coming out of the constructor could be in a "incomplete" or "invalid" state, and requires a second step to "initialize", you type would definitely be used incorrectly at sometime, by someone (which could probably be yourself).

in languages like C++ (or Java), you can' change the return type of a constructor, so a fallible constructor can only be implemented by throwing an exception on failure, (but some C++ people or organizations don't use exceptions). two phase intialization is invented just to overcome the language limitation.

but in rust, we don't have a C++ like "constructor" concept defined in the core language. instead, we treat certain associated functions as constructors purely by convention, and indeed a constructor can return any type you deem suitable, be it Result<Self>, Option<Self>, Box<Self>, thanks to the sophisticated type system and optimizer, (notably, ownership and move can guarantee you don't get unexpected copy of heavy resources, and better yet, many of the moves are actually eliminated by the optimizer)

so if your type must be initialized awaiting some Futures be ready, just make the constructor return type like:fn new() -> impl Future<Output = Result<Self>>, or, use a async function.

4 Likes

At this point all I can offer is that I strongly agree with everything above.

Well, that and, good question. Thank you for asking.

1 Like

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.