[HN Gopher] Understanding Rust futures by going way too deep
___________________________________________________________________
Understanding Rust futures by going way too deep
Author : tempodox
Score : 428 points
Date : 2021-07-26 06:26 UTC (16 hours ago)
(HTM) web link (fasterthanli.me)
(TXT) w3m dump (fasterthanli.me)
| the_duke wrote:
| For an excellent, in depth introduction to async in Rust I
| recommend this post [1], part of the "Writing an OS in Rust"
| series.
|
| This seems to be more of a hands on guide for the ecosystem.
|
| [1] https://os.phil-opp.com/async-await/
| tikkabhuna wrote:
| Another hands on guide I really rate is Tokio's [1].
|
| You create a very minimal Redis clone progressively by swapping
| out synchronous for async.
|
| [1] https://tokio.rs/tokio/tutorial
| beltsazar wrote:
| I've read many articles explaining Rust async and I think the
| best one is the async chapter of Programming Rust (2nd edition).
| It's not too daunting for someone new to async concepts, and yet
| comprehensive enough for someone curious about how Rust async
| works (future, waker, pinning).
|
| Amazon link: https://www.amazon.com/dp/1492052590
|
| Direct link to the chapter (if you subscribe to O'Reilly/Safari):
| https://learning.oreilly.com/library/view/programming-rust-2...
| Walther wrote:
| Thank you once again for writing such an excellent article <3
|
| In contrast to some other comments here, I love the narrative
| style. After all, these are half tutorials half entertainment -
| and the entertainment keeps it enticing. I would not have spent
| nearly two hours reading about the nitty-gritty of futures
| implementation details today if it weren't for the way you write
| about things.
|
| To put it the other way - if I wanted to read a super condensed,
| concise reference of how these things work, I would, you know,
| read a reference. The narrative style of building things on your
| own, solving problems as you face them, picking tools and
| libraries on the way, feels relatable as the everyday lived
| experience of software development. It feels appropriate for the
| medium - it's a blog after all!
|
| Besides, blogs are the perfect place to mention the tiny useful
| tools and libraries people might not have heard of. References
| and books might err on the side of being "neutral" and not making
| opinionated recommendations, but this can also lead to unknown
| unknowns. People don't know what they are missing out on!
| Luckily, blogs have more freedom here. Mentioning things like
| `cargo-edit`, `serde` and others can probably make some readers
| feel like "one of today's lucky ten thousand" - enjoying the
| newly-gained quality of life improvements.
| ordu wrote:
| Yeah! This article not just explains how async works, the
| author show research methods to learn how async works. How
| something works is transient knowledge, how to learn how
| something works is timeless priceless knowledge.
|
| The methods include strategically inserted panic!, some nice
| crates with examples how to use them... I cannot say I've
| learnt a lot about async, but I got few insights on
| technicalities of self-learning.
| [deleted]
| shantanugoel wrote:
| +1 I enjoyed the writing style thoroughly. It made
| understanding the concepts super simple and fun to go through.
| MrBuddyCasino wrote:
| _Gaze upon our work, and rejoice:_ pub fn
| try_join<A, B, AR, BR, E>(a: A, b: B) -> impl Future<Output =
| Result<(AR, BR), E>> where A: Future<Output =
| Result<AR, E>>, B: Future<Output = Result<BR, E>>
|
| I get why its like that, but I really wished this wasn't a
| typical Rust generics signature.
| magicalhippo wrote:
| I don't know any Rust, and that thing made perfect sense to me
| (compared to other things in Rust).
|
| How would you have preferred it looked?
| jcelerier wrote:
| Generics are about encoding supplemental bits of information in
| the type system. That information has to be spelled out
| _somewhere_
| cormacrelf wrote:
| Yes, however in my experience you typically have to write out
| constraints like these a bunch of times. Refactoring a
| generic trait with 10 implementations is a nightmare. A
| struct with a couple of variations on the constraints for its
| impl blocks is also painful beyond like one generic param. It
| has to be spelled out somewhere, but then at minimum
| somewhere else, and in general about 3-4 more times.
|
| I see why Haskell folks like their type level functions.
| tinco wrote:
| In Haskell I used to do this trick where if I wanted to
| neatly type annotate, but my function had some crazy
| signature, I'd compile the program, but passing the
| function into another function in an intentional incorrect
| way. The compiler would complain "expected A but got B".
| And I would simply copy B and make it the type annotation
| :P
|
| Nowadays the editor would help you do that. When I'm coding
| Rust the editor shows the types inline in a small font,
| which is very helpful.
| myrrlyn wrote:
| yeah, bounds written on the type decl _shouldn 't_ be
| repeated on the impl. the current typeck is not smart
| enough to do that but the ever-"nearly there we promise"
| replacement is. it'll land one day. they promise
| Ygg2 wrote:
| Do you have a better way to write the same constraints?
|
| Conceivably if there was a way to not repeat the future parts.
| drran wrote:
| It's easy to read, isn't?
|
| pub fn - public function
|
| <...> - declaration of types,
|
| A - type of first future,
|
| B - type of second future,
|
| AR - type of result of first future
|
| BR - type of result of second future
|
| E - type of error
|
| So, public function try_join accepts two futures, which my
| return <AR>esult and <BR>esult or <E>rror, and returns future
| which will return tupple with (<AR>, <BR>) or <E>rror.
| scoutt wrote:
| > It's easy to read, isn't? pub fn
| try_join<A, B, AR, BR, E>(a: A, b: B) -> impl Future<Output =
| Result<(AR, BR), E>> where A:
| Future<Output = Result<AR, E>>, B: Future<Output
| = Result<BR, E>>,
|
| Come on... "A", "B", "E", "a", "b"??? Naming stuff like this
| is the standard way? I mean, if I know nothing about what the
| code does, and I find this kind of function, I'll start
| swearing right away.
|
| Also, the function only does:
| TryJoin::Polling { a: State::Future(a),
| b: State::Future(b), }
|
| Which is clearer and shorter. Why even writing a function
| signature like that? It's longer and more complicated to
| understand than the code itself! I don't know much Rust, but
| since a semicolon is missing this is just a return value,
| right?
|
| So why not? let res = TryJoin::Polling {
| a: State::Future(fetch_thing("first")), b:
| State::Future(fetch_thing("second")), }.await?
|
| PS: I don't want to criticize, and I'm not a Rust literate,
| I'm just amazed with its complexity.
| gpderetta wrote:
| To be fair the full expansion of A and B are literally on
| line below.
| kmeisthax wrote:
| So, there's a few things to point out here:
|
| - The example you gave at the bottom won't really work,
| because enum variants aren't fully-fledged types on their
| own and they can't impl `Future`. Therefore, you can't
| `.await` them on their own. Furthermore, the point of
| `try_join` is to poll _both_ futures until one fails, which
| you can 't do with `async` syntax.
|
| - Rust requires that you spell out all generic parameters
| like this at function boundaries. It's technically possible
| to infer types across such boundaries, but that has the
| potential for significant changes to the typing of a
| function to go entirely unnoticed. In fact, I believe some
| of Rust's documentation specifically calls out problems
| Haskell had with inferring function signatures like this.
|
| That being said, you are correct that we could do this
| instead:
|
| ```pub fn try_join<FutureA, FutureB, ValueA, ValueB,
| Error>(future_a: FutureA, future_b: FutureB> -> impl
| Future<Output = Result<(ValueA, ValueB), Error> where
| FutureA: Future<Output = Result<ValueA, Error>>, FutureB:
| Future<Output = Result<ValueB, Error>>,```
|
| That _is_ slightly more readable.
| greenshackle2 wrote:
| I'm used to the convention of giving short all-caps
| acronym names to type parameters, so this is less
| readable to me, because I automatically assume that
| something named `Error` is a type, not a type parameter.
| scoutt wrote:
| Oh god. I guess Rust designers have not foresee a
| function taking 5 parameters.
|
| At this point, somehow, I'm starting to consider C++
| templates beautiful! Perhaps a signature form like:
| template <FutureA, FutureB, ValueA, ValueB, Error>
| pub fn try_join() ... etc.
|
| would be clearer at this point.
| paavohtl wrote:
| I don't think this is a _typical_ signature. On the contrary,
| it's quite exceptional. In my experience having more than 1
| type parameter in a function is quite rare in most code, unless
| you're building an advanced, composable library like a futures
| implementation.
| MrBuddyCasino wrote:
| I didn't mean "typical" as in "most Rust fn signatures are
| like that", obviously most functions are far simpler. Who
| would even claim that?
|
| I meant "you will only encounter this level of generics
| complexity in Rust" (disclaimer: I don't know C++). They
| can't be that rare either, I have not written a lot of Rust
| but already encountered similar constructs multiple times.
| But admittedly that might be partly due to no-std
| requirements.
| jen20 wrote:
| C#'s `Tuple<T1,T2,T3,T4,T5,T6,T7,TRest>` [1] would like a
| word!
|
| [1[: https://docs.microsoft.com/en-
| us/dotnet/api/system.tuple-8?v...
| richardwhiuk wrote:
| You can do: pub fn try_join<A: Future<Output =
| Result<AR, E>>, B: Future<Output = Result<BR, E>>, AR, BR,
| E>(a: A, b: B) -> impl Future<Output = Result<(AR, BR), E>> {
| diragon wrote:
| Rust truly is a better C++.
| zwirbl wrote:
| Haven't read this article yet, but I've enjoyed most of the
| previous ones from amos
| masklinn wrote:
| > I don't know! Why do they truncate stuff like that?
|
| Because Linux limits thread names to 15 bytes (not including the
| required terminal nul).
|
| Other unices are better though not great, macOS is 63 I think.
|
| By comparison Windows allows 32... kilobytes.
|
| Though "runtime" is probably what should be shortened here, "rt"
| is literally the name of the tokio features for configuring the
| runtime, so that would likely be more understandable than the
| trailing "-w".
| ArchieMaclean wrote:
| Based on my understanding from the article...
|
| Iterators change over space, Futures change over time.
|
| In iterator, every time you call 'next' you get a value until the
| end when you get nothing. In Future, every time you call 'poll'
| you get nothing until the end when you get a value.
| DixieDev wrote:
| Not related to async in Rust, but a 26 sec clean build time for a
| project with 69 dependencies and no code of its own just to get
| to the point where we can "do something useful" feels a little
| wasteful.
| pornel wrote:
| Async runtime, channels, tracing, backtraces. It does compile a
| lot of useful stuff ready for you to use.
|
| It's all cached, so consider it more of a library install time.
| kungito wrote:
| I'd say it's pretty unfair to take clean build time to consider
| doing something useful. 98% of my rust builds are incremental
| builds which take 10-15 seconds for a project I have been
| working on for 9 months full time and I think my dependency
| tree has easily 1000 dependencies.
| DixieDev wrote:
| True, it's not a real problem in most scenarios if
| incremental compile times are good. I still feel uneasy
| depending on so many other crates, but this seems to be a
| level of paranoia that others in the community don't share.
|
| Having 1000 dependencies sounds crazy to me! If there's a bug
| in even one of them that affects you then there's gonna be a
| lot of digging to figure out the cause, and possibly multiple
| pull requests to get it fixed. I think my CPU would spend a
| bit longer than 10-15 secs on the linker step, too.
| myrrlyn wrote:
| the reason for
|
| > I still feel uneasy depending on so many other crates,
| but this seems to be a level of paranoia that others in the
| community don't share. Having 1000 dependencies sounds
| crazy to me! If there's a bug in even one of them that
| affects you then there's gonna be a lot of digging to
| figure out the cause
|
| is that there is far, far more likely to be a bug in the
| version you write on your own to achieve the same goal than
| there is in a widely-observed library written by somebody
| who's chosen to specialize in that specific thing
| usefulcat wrote:
| > there is far, far more likely to be a bug in the
| version you write on your own
|
| In general I agree with this, but there is another
| relevant aspect to consider: something that I've written
| on my own for a particular project is also likely to be
| more purpose-built, and therefore simpler.
| hnlmorg wrote:
| In theory yes. But in practice that isn't always true.
| People often don't audit other modules on the assumption
| someone else had. Which means nobody ends up doing it.
| And if you end up with an ecosystem that favours more
| modules over fewer, you can end up with more modules than
| a given developer or team are willing to audit (a bit
| like "alarm fatigue" where if you have too many objects
| to check then people will inevitably just get lazy).
|
| Just look at how many C and C++ libraries are maintained
| by 1 individual and have almost no 3rd party oversight to
| see that Rust can't automatically make the claim you
| made.
|
| That all said, for anything complicated and/or directly
| security related, one should always check if there is a
| module first.
| db48x wrote:
| I look at it the other way around. You own any bug in
| your product whether it comes from a dependency or from
| code of your own; you have to fix the bug either way.
| Using a dependency doesn't reduce your responsibility,
| but it does reduce the amount of code that you have to
| write yourself.
| hnlmorg wrote:
| But if you are willing to own that responsibility then
| you should read the code you're importing to begin with.
| I know I do but I also know most people don't bother.
|
| I do acknowledge that there will always be bugs that are
| identified by your users but equally if you're not
| auditing your dependencies first then it's hard to argue
| that you're not just passing off that responsibility
| wholesale to your users.
| kungito wrote:
| It's always a tradeoff whether you want to read some
| other code or work on something else. Rust ecosystem is
| not that mature so for a few libraries I had to end up
| rewriting the thing myself with some fixes or without
| some bloat. I'm writing an application level thing and I
| need as many utilities as possible as I do not want to
| write all the layers for all the abstractions that end up
| in my product. Then when something breaks I investigate,
| offer a fix, open an issue or whatever. I'm not writing
| something that requires too much reliability or whatever,
| the utility is elsewhere.
| volta83 wrote:
| I rather have 1000 dependencies than re-implement all those
| 1000 dependencies myself, chase all the bugs that have
| already been ironed out in those, etc.
|
| My time is worth more than my computer's time.
| fasterthanlime wrote:
| Compile/link times are definitely a discussion topic.
| Here's some quick tips: * Incremental
| compilation helps locally, not so much in CI, unless you
| save/restore the whole cache which gets large quickly and
| evicting the out-of-date objects is non-trivial. * In
| CI, sccache helps, but not as much as I'd like: there's a
| bunch of things that are non-cacheable, notably crates that
| pull in & compile C/C++ code (I'd trade 2 c-bindings crates
| against 12 Rust-only crates any day for that reason alone)
| * Splitting stuff across different crates helps
| parallelizing the build (and caching it better), which may
| be one of the reasons some projects end up having "1000
| dependencies" (although I've rarely seen upwards of 600)
| * For incremental builds, linking does become the
| bottleneck. Full LTO is especially slow, Thin LTO is
| better. Switching to LLD improves thing. I'm hopeful that
| mold will improve things some more. * Re multiple
| PRs: thankfully crate families tend to live in the same
| repository, so fixing something across both tracing /
| tracing-subscriber could be a single PR, for example.
|
| I wish the Rust community invested more in build caching,
| but even with the current state of things, there's often
| steps you can take to make things better.
| styluss wrote:
| Have you tried sccache?
| https://github.com/mozilla/sccache
| riquito wrote:
| It's his second bullet point
| jokethrowaway wrote:
| This is a pretty great article but I don't get the hate for
| futures not executing immediately and requiring an .await.
|
| It's great to have pure futures-returning functions and being
| able to isolate side effects easily.
|
| I find it much easier to reason with (coming from mainly JS,
| where everything is executed as soon as a promise is created).
| the__alchemist wrote:
| What are y'all's thoughts on Async in embedded? A portion of the
| Rust embedded OSS community really likes it as an abstraction
| over interrupts, critical sections etc. I've been burned by over-
| complexity and coloring problems with it before, eg in web
| programming.
|
| Do you think it's a good fit? Use-case-dependent? Maybe for
| things like RF?
| steveklabnik wrote:
| We don't need it, so we don't use it. I think it's fantastic
| that it's possible, and I think that if you do need it, it's
| great to have it.
| floatboth wrote:
| There is an executor project: https://github.com/embassy-
| rs/embassy
|
| I'm very excited about this for one simple stupid reason:
| sleep(). Awaiting a timer delay deep inside some code is gonna
| be _amazing_. With typical sync code, you basically have to
| split your code and queue up the next work somewhere that would
| be picked up by the timer interrupt... basically doing the
| whole state-keeping that async would do for you.
| the__alchemist wrote:
| That sound like a nice advantage. I'd like to give this a
| shot on a future project. Its creator and I share some API
| design ideas, like using less typestate programming than
| other conventions, but I haven't used Embassy due to being
| cautious of Async. (The Typestate thing is a tangent; short
| explanation is it lets you check for misconfigured pins etc
| at compile time, but makes syntax significantly more verbose
| and harder to refactor)
| thrwyoilarticle wrote:
| >When deciding which article to read during their coffee break,
| people usually open several websites at the exact same moment,
| and read whichever article loads first.
|
| >And that's a fact. You can quote me on that because, well, who's
| going to go and verify that? That sounds like a lot of work. Just
| trust me on this.
|
| Sure, but I click away when it hurts to read.
| yodelshady wrote:
| I am surprised Rust doesn't lean into the type system more for
| declaring async, as I really like that way of framing it.
| Admittedly, I'm probably not writing ```impl Future<Output =
| Result<(), Report>> + 'a``` all that much in practice.
|
| I like fasterthanlime's writeups but it does have one particular
| bugbear for me, that seems _particularly_ common for Rust (and
| Python, to be fair) feature writeups: environment-based yak
| shaving because the author likes the mostly-unrelated library
| <X>. The very first thing that happens if I try to reproduce this
| code is a build error for cargo-edit, which is _totally unrelated
| to the feature being taught_ , yet if I wanted to follow the
| writeup, I'd have to fix it.
|
| I do _really_ have this bugbear, particularly with Rust tutorials
| ohazi wrote:
| > I am surprised Rust doesn't lean into the type system more
| for declaring async, as I really like that way of framing it.
| Admittedly, I'm probably not writing ```impl Future<Output =
| Result<(), Report>> + 'a``` all that much in practice.
|
| Futures was stabilized before the async syntax, so this used to
| be the _only_ way you could do it. But those were definitely
| the bad old days.
|
| A handful of (brave) developers and library writers wrote async
| code like this back then when they really needed to, but the
| vast majority waited for async syntax to stabilize. Those state
| machines get ugly _real_ fast.
| j1elo wrote:
| I stand by my opinion that any kind of documentation or
| tutorial should pass a validation step where the author does
| copy/paste of all their commands into a clean Docker container
| or VM image. If any error happens, your work is not done yet.
|
| If you need to instruct users to install a compiler or an extra
| tool, so be it. It just must work as-is on a clean system (for
| which using Docker is easiest for me, but a clean VM or any
| other alternative is fine too).
| gmac wrote:
| Preferably the author doesn't copy and paste: preferably
| there's a documentation build step where everything gets run,
| relevant outputs get inserted into the docs, and any errors
| get caught.
|
| This is how my docs for Zapatos[1] work, for instance. :)
|
| [1] https://jawj.github.io/zapatos/
| j1elo wrote:
| It is probably too much to ask everyone follow the same
| approach, so I'll be happy if people just test their own
| commands by hand. But your doc build step that validates
| code and catches errors? That's the ideal setup, for sure.
| Great job!
| chromatin wrote:
| > I stand by my opinion that any kind of documentation or
| tutorial should pass a validation step where the author does
| copy/paste of all their commands into a clean Docker
| container or VM image. If any error happens, your work is not
| done yet.
|
| Very much this. We often write scientific software with
| (command-line) instructions for nontechnical or sort-of-
| technical users and have learned from experience to not
| assume anything about the user's environment, or background
| knowledge, and to try to replicate our documentation's
| instructions line-by-line!
| richardwhiuk wrote:
| This article takes ages to get to futures because the writer
| seems to want to go on some tour of Rust crates first.
| cormacrelf wrote:
| IMO if your article is long enough that it crashes
| MobileSafari, it should have a table of contents. Or it
| should be a book chapter. It's a really obvious criticism of
| all of fasterthanlime's posts that scarcely bears repeating
| at this point but they're not getting any shorter. I get that
| he has a lot to say but I just don't have time to wade
| through all of that. What slice of Rust users are both such
| noobs they haven't heard of cargo-edit and can't Google it,
| but also so advanced they are interested in implementing
| Future manually to deepen their understanding? It's ok to
| teach both things but why together?!
| myrrlyn wrote:
| > What slice of Rust users are both such noobs they haven't
| heard of cargo-edit and can't Google it, but also so
| advanced they are interested in implementing Future
| manually to deepen their understanding?
|
| My colleagues. Many people are skilled programmers jumping
| into obscure problems with only a baseline level of
| familiarity with the greater environment.
| Filligree wrote:
| Or for example me.
|
| cargo-edit looks useful. None of the tutorials I've
| skimmed have mentioned it.
| fasterthanlime wrote:
| Ok I promise I'm going to stop replying to those comments
| (because as you pointed out they show up on every post),
| but! Rust is not the only language with a decent type
| system out there.
|
| I can definitely see some ML/Haskell/Scala/etc. folks who
| would quickly pick up on all the Future stuff, drawing
| parallels with their usual language of choice, yet being
| completely unaware of all the nice tooling around Rust.
| It's one of its main selling points for me!
|
| Re cargo-edit specifically, it also lets me stay in flow
| while writing these: instead of having to repeat "we'll
| just edit Cargo.toml, make sure to have that under
| [dependencies], uh this time we need a feature so the
| right-hand-side needs to be an object, not a string" -
| instead I can just copy into the article the actual
| commands I run on my side, and if a quick paragraph about
| where that subcommand comes from unblocks even one person
| then it's worth it.
| nindalf wrote:
| I wouldn't worry too much about it. You have your style,
| and it clearly works for the people who like your work.
| Everyone likes different things, and it doesn't make
| sense to force homogeneity. It's ok to cater to niches.
| WJW wrote:
| FWIW, I fall exactly into that niche. I've never written
| a line of Rust in my life but am quite competent with
| Haskell and Ruby and have dabbled in at least half a
| dozen others. Seeing everyday `cargo` use made me think
| of bundler and the Future/Result type signatures were
| easy to map onto Async/Either and the like.
|
| So yes, it's a long article but I didn't mind that in the
| least. Keep it up!
| fasterthanlime wrote:
| Not to worry, we also spend some time messing with strace and
| GDB. I see it more as "giving a working knowledge of Rust"
| than a distraction. Some of these crates/tools are
| lifechangers, I wouldn't want folks to miss out on them.
|
| I'm sorry yodelshady has run into a build error for cargo-
| edit (was it OpenSSL? screw OpenSSL) but also: the more folks
| run into these issues and report them, the sooner they're
| fixed. Also! I think cargo-edit should just be adopted by the
| default cargo distribution because it's all-around really
| good.
| michael_j_ward wrote:
| > we also spend some time messing with strace and GDB
|
| Yes, and if I had learned about these a couple months ago
| it would have saved me ~8 hours tracking a bug down. So,
| thank you.
| PudgePacket wrote:
| I only learnt about the logging and tracing crates existed
| from this blog post and I've already started using them, so
| thank you!
| hmfrh wrote:
| The Zero to Rust[1] series also has a fairly
| comprehensive look into these.
|
| [1]: https://www.lpalmieri.com/posts/2020-09-27-zero-to-
| productio...
| steveklabnik wrote:
| Tracking issue on cargo-edit here: https://github.com/rust-
| lang/cargo/issues/5586
|
| I too really, really want this. If only I had the energy to
| work up some patches...
| mikro2nd wrote:
| I have to agree with the first comment: Speaking as someone
| who was a tech trainer and writer of course materials,
| tutorial, etc. for a couple of decades, if ``carge-edit``
| is not core to what you're trying to teach, _leave it out_.
| Get your own desires (ego) out of the way, and stick to
| teaching what you need to teach. Leave the distractions
| /side-tracks/proselytising to a separate lesson. You think
| of the lesson as "Giving a Working Knowledge of Rust"?
| Great! Then title it accordingly and don't dress it up in
| "futures" camouflage -- you're doing your readers/learners
| a disservice.
|
| Many, _many_ tutorials make this mistake.
| kbenson wrote:
| > Then title it accordingly and don't dress it up in
| "futures" camouflage -- you're doing your
| readers/learners a disservice.
|
| In their defense, the title is "Understanding Rust
| futures _by going way too deep_ ", and I think advice and
| tangents on best practices modules is easily covered by
| "going way too deep".
|
| > you're doing your readers/learners a disservice.
|
| Not every tutorial needs to be the same, cater to the
| same type of person, or try to explain things in the same
| manner. I think the bigger disservice to readers/learners
| would be to homogenize tutorials into what you think is
| best. That might work best for a certain type of person
| at a certain skill level, but that doesn't mean everyone
| will be served well by that. And as the comments here
| illustrate, it's not like there's a dearth of Rust
| futures tutorials and explanations. There's definitely
| room for a rambling, informal, irreverent, meandering
| take (it's the only thing that kept me reading until the
| end, or even past the first page or two).
| jfrankamp wrote:
| This isn't a tutorial, nor a training, nor a course
| though, this is a cave exploration. Its going down the
| wrong paths, multiple times on purpose. So pack your bag,
| get your tools in order, we may not return. I really like
| this style, the wrong paths/side tracks have so much to
| teach us (more than the right paths).
| actuallyalys wrote:
| As someone who's been a technical writer (albeit for
| years rather than decades), I think this is often good
| advice, but not here. As other people have pointed out,
| this isn't trying to be a Futures 101 or Futures for
| Total Beginners. The title or opening could maybe be
| clearer about its scope (although I think "way too deep"
| at least implies the author isn't covering the topic as
| directly or succinctly as possible), but I think the
| digressions are interesting to Amos' target audience and
| part of his style.
| freeopinion wrote:
| You have mistaken this for a tutorial.
| SAI_Peregrinus wrote:
| I'd say this is a good explanation, but a bad tutorial[1].
| Which is fine, they're different things. But if you _want_
| it to be a tutorial it should be focused on just Rust
| Futures, and the other stuff should be separated out.
|
| [1] https://documentation.divio.com/
| Zababa wrote:
| On the other hand, I really like that way of giving "best
| practice" advice, as it's really useful advice. You end up with
| a deeper understanding of futures, but also concrete advice
| that you can apply easily.
| DiabloD3 wrote:
| Woah, he uses Iosevka for his mono font. :D
|
| Edit: Whoever is downvoting, Iosevka is one of the favorites of
| the HN crowd, and also my own daily driver. It is worth taking
| for a spin if you haven't yet.
| perryizgr8 wrote:
| > 107 minute read
|
| Hmmm... that is truly way too deep.
| pictur wrote:
| As someone who has never played a pass, I have a question. Every
| article I see about rust says it's all very simple. this is
| something that can change from person to person yes, but is it
| like that for you? I wonder what people who play with rust think
| about it. (this is just a question please don't take it as an
| offensive comment)
| umanwizard wrote:
| IMO Rust is much easier and simpler than C++, but much harder
| and more complex than any managed GC language.
| grumblenum wrote:
| It's a west-coast tech industry consortium language that is a
| mashup of subsets of SML, C++ and Cyclone with some very strong
| opinions about aesthetic differences. "Simple" is not a good
| description. Lisps are simple. Rust, Java, C++ & friends are
| not. Also, the core paid promoters of rust are almost all
| alumni of the Ruby on Rails hype-train. You can judge for
| yourself if their promotion of rails was grounded in truth.
| moldavi wrote:
| Rust has paid promoters?
| steveklabnik wrote:
| We do not, but sometimes people who want to disparage me,
| Rust, or both, say stuff like this. It was said a lot more
| often in the earlier days.
| grumblenum wrote:
| Well, I certainly wasn't speaking about you specifically.
| However, did you not say that language promotion is what
| you do and that you quit Mozilla for not paying you
| enough for it here:
| https://steveklabnik.com/writing/thank-u-next ?
| steveklabnik wrote:
| "promotion" doesn't appear in that post. My job was
| writing documentation. I did say that I was considering
| moving into evangelist/growth roles. My next job wasn't
| those two though, it was PM.
|
| I guess you were trying to disparage Yehuda, then?
| grumblenum wrote:
| I mean that you are one of several. Hence the running
| joke is the "Rust Evangelism Strike Force" and not "that
| one rust guy."
|
| An evangelist/growth focused role is exactly what a
| promoter is. If you spend large numbers of typical work-
| hours, which I'm assuming you're paid for, on social
| media to promote something, like Rust, or you go to
| conferences and events to speak publicly in promotion of
| something like Rust, then a "paid promoter" seems like a
| pretty accurate description.
|
| Is that disparaging? Is that not what you are doing right
| now?
| steveklabnik wrote:
| > An evangelist/growth focused role is exactly what a
| promoter is.
|
| Right. _move into_. Because that was not a part of my job
| description at Mozilla. They didn 't dislike the stuff I
| was doing, but it's not my _work_.
|
| The disparagement is the implication of lying:
|
| > You can judge for yourself if their promotion of rails
| was grounded in truth.
| grumblenum wrote:
| Given a 15 year retrospective, would you say that Rails
| lived up to the hype? If you think so, then there is
| nothing "disparaging" in that comment at all. If you
| don't think so, then doesn't that mean a reader should
| not regard such promotion with confidence? No need to be
| defensive.
| floatboth wrote:
| SML doesn't have typeclasses/traits, so it's fair to say
| "Haskell" instead.
| grumblenum wrote:
| SML has signatures. In the absence of HKT, I think it's not
| a fair comparison. Most popular languages have interfaces
| even if not by that name. Haskell, Scala and C++ are
| special in that you can describe an interface for
| interfaces. I'm sure I'm not giving due credit to others.
| Argorak wrote:
| (For context: I teach Rust since 2015)
|
| Rust is "simple" in that it is based on a few solid principles.
| Data with layout, Ownership of the data and the distinction
| between sharing and mutability (through immutable references
| and mutable references). Most of the interesting API in _some_
| way leans into that. So, the _basics_ of Rust are indeed quite
| constrained.
|
| But that's "simple" in the sense of "Ruby is simple, everything
| is objects and message passing".
|
| But then: Generics introduce a ton complexity on top, because
| they open a space where you are _potentially_ in a borrowed
| _or_ an owned situation. There's tons of tiny optimisations and
| protocols: for example that `Box<[u8]>` exists and turning it
| into `Vec<u8>` comes basically for free. There's tiny details
| like compiler assists that sometimes trigger and sometimes not.
| But even Generics can also be seen as an application/extension
| of the basic principles.
|
| And then, there's tons of tooling and language that you need to
| know. Standard traits and features of the stdlib. Clever
| applications of Ownership based management for handles.
|
| And particularly Rust is (currently) not _easy_, because the
| programming environment has fundamentals that are unusual to
| program that you cannot bypass as a beginner. That actually
| changes, the more those practices get known to people and
| individuals can teach each other rather than finding out
| themselves.
|
| I think what people say when they say "Rust is simple" is that
| they can break down any house to a limited set of bricks. That
| is certainly true. But that needs a level of proficiency with
| the language. So, telling beginners "look at Rust, it's simple"
| is harmful - it's full of combinations and applications of its
| language core and it will take quite some time to learn
| breaking that down for people and figure out which tool is for
| which moment.
| fasterthanlime wrote:
| "Simple" can mean many things.
|
| For me Rust is "simple" because it has great tooling / great
| diagnostics, so when I get something wrong, most of the time it
| can tell me exactly what it is (and how to fix it!), and only
| occasionally does it send me down a rabbit hole.
|
| Rust is also "simple" because it's memory-safe - if I can get
| something to compile (without unsafe code), then I know there's
| no use-after-free, double-free, buffer overflows, etc. I can
| concentrate my mind on the business logic (where bugs still can
| and do happen).
|
| Finally, Rust is "simple" because it lets me build abstractions
| so I can see more clearly what I'm doing. At work we had a Go
| codebase full of goroutines and channels - I got tired of it
| and did a proof of concept in Rust: now it's just one async
| Stream, you can see the data flow clearly and worry about each
| stage of the pipeline in isolation, instead of having to jump
| across many different source files.
|
| But no, it's not all very simple. There's plenty to learn, and
| some of the core concepts (ownership / lifetimes) are fairly
| hard to wrap your mind around, even if you've encountered
| something similar in other languages. My take is that it's
| worth it - you'll be very slow at first, but as you get more
| comfortable with it, so will you get faster.
| dicroce wrote:
| I don't think it's simple. I find lifetimes especially
| challenging. I love rust, but sometimes I am remarkably
| unproductive in it because the compiler is so strict. Honestly,
| sometimes I think I need flash cards for memorizing how to deal
| with particular compiler errors.
| Argorak wrote:
| Lifetimes are an interesting illustration. They are
| conceptually surprisingly simple (they draw regions in time
| and check if one region is clearly smaller than another), but
| as a language feature very weird, as they are essentially a
| declarative language in an imperative setting. A lot people
| struggle with them more because they can't really _place_ the
| feature rather than applying it.
| hmfrh wrote:
| > this is something that can change from person to person yes,
| but is it like that for you?
|
| In my opinion it really depends on your background.
|
| For example, Rust uses the `i32` type as the standard integer.
| If you come from a C/C++ background this is probably not that
| weird, you probably know how many bits there are in 4 bytes off
| hand, there's `int32_t` standard types and you probably have
| experienced not wanting an integer with a variable size that
| depends on the platform.
|
| If however you come from Python, Javascript, or maybe even
| Java, this might range from a little weird to very weird.
| Python only has the `int` type, no unsigned types and you might
| not know how many bits make up a "standard" integer, or even
| exactly how bits, signedness and integer sizes fit together.
| Java doesn't have unsigned types and doesn't have issues with
| sizes depending on the exact platform, so they might not
| understand why you would want the amount of bits right there in
| the type name.
|
| This is just for the standard integer type. If you consider how
| many design decisions are a direct result of working on low
| level, high correctness required C++ code, the "simplicity"
| could range from completely simple to very much not simple.
| [deleted]
| [deleted]
| aarongolliver wrote:
| Not sure a better place to ask this, but we're getting to the
| point in most OSs where basically anything you want can finally
| be done truly async (non-blocking).
|
| Except that DNS apparently still blocks[0], so usually things
| farm DNS requests off to their own blocking thread pools (the
| author ends up disabling DNS just so they can "prove" everything
| works with just a single thread)
|
| What's so fundamentally difficult about writing an async/non-
| blocking DNS resolver? Is it just a lack of a real need for it?
|
| [0] (quote: People have been trying to build asynchronous DNS
| resolvers for decades without success. Can it be done? Yes. Has
| it been done? No. )
| https://gist.github.com/djspiewak/46b543800958cf61af6efa8e07...
| aarongolliver wrote:
| I have found this comment on liburing[0] which clarifies some
| things for me. So is it because something like getaddrinfo is
| not just a simple operation, but a hodgepodge of stuff like
| "first try nscd, then read resolv.conf, then make a bunch of
| requests using one of many different protocols"?
|
| I think I have a lot more to learn about DNS...
|
| [0]
| https://github.com/axboe/liburing/issues/26#issuecomment-738...
|
| > [re: implementing getaddrinfo] It's not planned because it's
| not a single operation but a complex beast reading files,
| exchanging messages, etc. IMHO, as it's not a single operation
| it fundamentally doesn't fit liburing, but implementing under
| some framework on-top would be more viable.
| jgehrcke wrote:
| There is real need, and there are solutions.
|
| NodeJS has a built-in DNS resolution API which is fully async /
| libuv-cooperative:
| https://nodejs.org/api/dns.html#dns_dns_resolve_hostname_rrt...
|
| Other async runtimes bundle libs like c-ares to implement non-
| threadpool-based async DNS.
|
| quoting the nodejs docs: "These functions are implemented quite
| differently than dns.lookup(). They do not use getaddrinfo(3)
| and they always perform a DNS query on the network. This
| network communication is always done asynchronously, and does
| not use libuv's threadpool."
| otabdeveloper4 wrote:
| On the OS level there is no difference between "sync" and
| "async". They become different in programming language
| runtimes.
| lights0123 wrote:
| Not really. mkdir(2) is definitely sync, io_uring has been
| called asynchronous since the start, and its predecesor has
| asynchronous in the name: https://lwn.net/Articles/776703/
| aarongolliver wrote:
| There is a difference between blocking and non-blocking,
| which is what I am asking about. Language runtimes apparently
| cannot provide non-blocking DNS (as evidenced by this
| article, and the other one I linked which was on HN a week or
| so ago).
|
| DNS seems like it perfectly fits the model of "give me a
| buffer (to hold the resolved IP), and I will wake you up when
| it's filled". Maybe io_uring (/ IOCP?) already can support
| this, and these articles are just mistaken about the current
| (or soon-to-be) state-of-the-art? Or is there some
| fundamental reason about DNS that make writing a non-blocking
| resolver very very difficult?
|
| It's just very odd to me that userspace apps are creating
| their own blocking thread pools just to run DNS stuff, when
| they can do seemingly everything else with just a single
| thread if they wanted to.
|
| (edited a few times, sorry if I caught someone who was mid-
| reply)
| layoutIfNeeded wrote:
| What an obnoxious style of writing.
| masklinn wrote:
| Don't read it? Some people enjoy amos' style, others don't.
|
| If that's not your cup of tea you can just gravitate other
| presentation styles, it's not like that's in short supply.
| libria wrote:
| > What an obnoxious style of writing.
|
| It's good to see counter viewpoints but share what you or
| others would be looking for instead.
|
| "This sucks" isn't helpful.
|
| "This part sucks but would be awesome if it {did this}" is.
| codezero wrote:
| I usually can't keep my focus in an article that is so long,
| but the narrative style helped keep me hooked through the
| entire thing.
| Subsentient wrote:
| The problem with analyzing stuff like this about Rust, is that
| even Rust itself has no idea how it works, or what syntax and
| semantics actually mean.
|
| Rust doesn't merely lack a language standard, its reference and
| advanced documentation is also a very unfunny joke. You can learn
| just enough to have some idea of what you're doing, and then
| you're stuck huffing unicorn queefs because nobody including the
| compiler devs knows the exact rules on how syntax is supposed to
| work.
|
| Magical shortcuts, syntax, and borrow checker tricks are added
| and removed at random with no rhyme or reason, and Rust severely
| punishes the programmer for wanting to know how the language
| actually works, since there are usually no answers, or worse,
| wrong answers, for them to find.
|
| I still use Rust because the memory safety without a GC is
| wonderful, but please, don't even try to make it look like Rust
| has some official documentation or behavior. It most definitely
| does not, and what really disturbs me is how so many of the Rust
| community _don 't even want a standard_.
|
| So OP, everything you've just done, will be rendered obsolete and
| woefully wrong in a couple years when Rust serves up another
| opaque unicorn-burger.
| pitterpatter wrote:
| >Magical shortcuts, syntax, and borrow checker tricks are added
| and removed at random with no rhyme or reason
|
| Everything else aside for now, this is just patently false.
| There's a well-established RFC process for any such changes to
| the language/compiler/standard library.
| nynx wrote:
| What? Are you sure you're looking at the right language? Or
| maybe you've confused stable rust and nightly rust?
| Subsentient wrote:
| No, I'm definitely on the right language. For example, lots
| of magical implicit reborrows with fuck all in the
| documentation, pattern matches and specifiers with no formal
| behavior defined, lints that change constantly. I do use
| nightly generally, simply because stable is crippled in
| features, but the same issues apply to stable.
|
| I should mention that even when they adjust these things in a
| stable release, they never fix the documentation to reflect
| it. And in the case of many of these things, they aren't
| documented at all, except perhaps a couple sentences about
| their existence.
| myrrlyn wrote:
| PRs welcome!
| Subsentient wrote:
| These issues cannot be fixed by merely updating the docs
| for a few items. (and frankly I don't contribute much to
| big FOSS projects because I've had bad experiences with
| big projects before)
|
| This can only be fixed by A. _Requiring_ that all syntax
| changes, no matter how small, are _fully_ documented
| _before_ they reach stable or even beta, and B. Eventual
| standardization, even if the reference implementation
| ends up being more cutting edge.
|
| Rust devs also need to think more about how they're going
| to document a feature before they add it. Like for many
| of the implicit reborrows, they're done in non-obvious
| places and not done in others, with no pattern to where
| it's done and where it's not. That kind of implementation
| is _extremely_ painful to document or standardize. Rust
| needs to think more in terms of _rules_ for syntax,
| rather than instances of a particular shortcut. Rather
| than adding a standalone instance, you should edit the
| rules so that instance is covered.
| ben0x539 wrote:
| Are you interested in standardization for its own sake or
| as a forcing function for exhaustive documentation?
| Subsentient wrote:
| Both, though mostly documentation. To me, a standard _is_
| the documentation. The fact I have to read rustc source
| to find syntax is frankly an abomination. A standard
| defines syntax and grammar in ways that a html reference
| page _never_ does. It doesn 't matter as much for
| "fluffy" languages like Python or Lua, but it's very
| important for a systems language.
|
| I also want standardization to make writing alternative
| conforming compilers easier. I strongly dislike the
| attitude of some Rust maintainers, and a standard is a
| useful tool to forcibly remove some level of control from
| their hands.
| CJefferson wrote:
| While this rant is excessive, I do see some of the
| annoyance, for example looking at: https://doc.rust-
| lang.org/core/cmp/trait.PartialOrd.html
|
| The top talks about lt, le, gt, ge, but then the docs
| below talk about '<' and '>', which I assume are lt and
| gt? But then there seems to be no requirements in le and
| ge? I assume everything needs to be consistent?
|
| Also (relating to auto-ref), why does 'a<b' work, when
| the trait takes a reference?
|
| EDIT: Some of this is revealed if I scroll down and look
| at the definitions of 'lt' and friends, but I'm already
| pretty confused at the top.
|
| EDIT 2: This really wasn't worth the effort of defending,
| but I made an issue with my comments on PartialOrd.
| [deleted]
| bob1029 wrote:
| Documentation and roadmap are the 2 make-or-break things I look
| for in a language/framework/tool. If one of these things is not
| satisfied, I have an incredibly hard time convincing myself to
| invest time.
|
| I have taken a look at the Rust documentation, and I just can't
| see myself participating at this point because of it. The
| roadmap is also unclear to me. I google 'Rust Roadmap', and
| guess what the first result is?
|
| https://rust.nolt.io/roadmap
|
| So far a video game's roadmap is ranked above that of this
| language. I had to search for 'rust-lang roadmap' to get a good
| top hit... Which brought me here:
|
| https://blog.rust-lang.org/2020/09/03/Planning-2021-Roadmap....
|
| > The core team is beginning to think about the 2021 Roadmap,
| and we want to hear from the community. We're going to be
| running two parallel efforts over the next several weeks: the
| 2020 Rust Survey, to be announced next week, and a call for
| blog posts.
|
| A call for blog posts. Beginning to think about...
|
| As a .NET developer, this honestly sounds like a dumpster fire
| to me. Who is actually in charge? What is the vision for 2025?
| How do you explain your software technology roadmap to your
| customers when you are using Rust and have to operate in
| contract lifetimes of 5+ years?
|
| Clearly, I don't know the first goddamn thing about the Rust
| ecosystem or why I would want to use it. I am just a dirty .NET
| plebian looking in from the outside. It doesn't look very
| compelling right now. Can someone correct my perspective on
| this? I am open to it. There must be some value I am missing.
| Maybe Rust just isn't for the "enterprise", or whatever boring
| niche box I seem to be stuck living in these days.
|
| There are obviously use cases and happy developers out there.
| Don't let me get in your way.
| myrrlyn wrote:
| every time this comes up i just have to ask
|
| - what do you think a language standard is or does
|
| - what languages with standards do you think standardization
| has helped (this is a trick question! do not answer "c" or
| "c++"!)
|
| - in which languages with standards is a plurality of code
| written to that standard? (this is also a trick question! do
| not answer "c", "c++", or "javascript"!)
| nicebyte wrote:
| a "language standard" is something i can use to hold
| implementation developers accountable. it doesn't matter if
| it's an actual international standard, or just a document on
| the internet. I want a dry, exhaustive and systematic
| description of the features and intended behaviors. Refer to
| the Vulkan spec
| (https://www.khronos.org/registry/vulkan/specs/1.2/html/) to
| get an example of what i consider a good specification.
|
| The rust docs don't currently meet that bar. They're quite
| WIP, and I imagine someone hitting a particular edge case
| will not necessarily be well equipped to understand whether
| the behavior they're observing is intended, a bug in the
| implementation or something else entirely.
| mjw1007 wrote:
| Yes.
|
| There is a great deal of written information about Rust-
| the-language which exists only in compiler comments, RFCs,
| bug reports and internals.rust-lang.org threads (often
| slightly stale in all cases).
|
| It's Rust's greatest weakness.
|
| But "every time this comes up" the discussion somehow gets
| sidetracked into arguments about standardisation, even in
| cases (such as this thread) when it's clear that what the
| ranter cares about is accurate documentation.
| nicebyte wrote:
| and to answer your other questions - Java and Python both
| have what I consider good, detailed specifications (which one
| could call "standards").
| pittmajp wrote:
| This is silly. That's like saying that speed limits don't
| work because everybody goes over them. Even if people don't
| 100% comply with standards, the fact that they exist reigns
| in peoples' behavior more so than if there wasn't one at all.
| jokethrowaway wrote:
| I assume your criticism revolves around breaking changes as
| what you mention is simply not true; there is plenty of
| documentation and language definition and I never found an
| issue.
|
| Development languages evolve all the time. It's normal, the
| same happens to human languages.
|
| I can't even say Rust is changing that much (especially
| compared to JS, my main work language).
___________________________________________________________________
(page generated 2021-07-26 23:01 UTC)