[HN Gopher] Rust: A Critical Retrospective ___________________________________________________________________ Rust: A Critical Retrospective Author : sohkamyung Score : 419 points Date : 2022-05-19 10:56 UTC (12 hours ago) (HTM) web link (www.bunniestudios.com) (TXT) w3m dump (www.bunniestudios.com) | est31 wrote: | I wonder what the author means by the alloc crate not being | stable? The alloc crate is stable since 1.36.0: | https://github.com/rust-lang/rust/blob/master/RELEASES.md#ve... | | Regarding the reproducible builds concern around paths being | integrated into the binary, a flag exists to get rid of paths: | --remap-path-prefix | | https://doc.rust-lang.org/rustc/command-line-arguments.html#... | | On nightly, there is also remap-cwd-prefix added by the chromium | team to address some of the shortcomings with remap-path-prefix: | https://github.com/rust-lang/rust/issues/89434 | | Overall I'm really impressed that an individual wrote 100 | _thousand_ lines of Rust. That 's a lot! | celeritascelery wrote: | > I wonder what the author means by the alloc crate not being | stable? The alloc crate is stable since 1.36.0: | | He is referring to the allocator api[1], not the std lib module | | [1] https://github.com/rust-lang/rust/issues/32838 | est31 wrote: | It doesn't seem to me that this feature is what the blog post | is referring to: | | > I often ask myself "when is the point we'll get off the | Rust release train", and the answer I think is when they | finally make "alloc" no longer a nightly API. At the moment, | `no-std` targets have no access to the heap, unless they hop | on the "nightly" train, in which case you're back into the | Python-esque nightmare of your code routinely breaking with | language releases. | | You can absolutely do your own allocator with no-std. All you | need for this is the alloc crate and the global_alloc | feature, while global_alloc was stabilized before the alloc | crate. Then you can call your own custom OS routines from | that global allocator. No need to fork std over that. | | Now, maybe their custom use case needs something different, | and then it's a fair criticism, but for that I would have | expected a different wording of the issue, hopefully together | with a more detailed explanation of those use cases and how | the stable part of the existing alloc crate does not meet | them. | throwawaymaths wrote: | If, like OP, you're writing an operating system (or a | language VM) it is absolutely a thing that you will want to | have different allocators for different use cases, so being | able to set a global allocator is "not quite enough". You | will want certain generics (like hashes) to be able to take | advantage of different allocators, or even different | instances of allocators (say, give each thread it's own | arena). This is very not easy in rust, which effectively | requires data structures to be associated with specific | allocators at the type-level - which makes code sharing | between the "same" data structure tied to different | allocators quite difficult. | | For reference, the Erlang VM, which is often joked as being | "an operating system unto itself" has 11? IIRC allocators. | est31 wrote: | The rust compiler makes use of custom arenas for | allocation, quite heavily in fact. And does it without | using the nightly-only custom allocator _alloc_ types. | Instead, there are functions that let you build | structures inside the arena, plus a bunch of macro logic | that builds on it. And while rustc generally uses a lot | of nightly features, there is nothing fundamental about | it that requires nightly. | | Also, again, it's a fair concern that you want to be | doing custom allocators, but this is not the same as | claiming that no-std applications can't use the heap at | all, which is what the blog post did. For simple heap | usage, a global allocator is enough. | throwawaymaths wrote: | 12 allocators: | | https://www.erlang.org/doc/man/erts_alloc.html | CryZe wrote: | You can write libraries against alloc on stable, but not any | executables, because executables not using std need to specify | the alloc_error_handler, which you can't do on stable yet: | https://github.com/rust-lang/rust/issues/51540 | est31 wrote: | Oh I see, I stand corrected then. Thanks for pointing that | out! | ntoskrnl wrote: | Yep, this is a great article, but that section (the whole "Rust | Isn't Finished" section) jumped out as a place where there were | some simple ways he could have made his life easier. It could | also have been a failure of the Rust community to teach a good | workflow. | | You don't need to force every contributor to upgrade every six | weeks in lockstep, since releases of Rust and std are backwards | compatible. Upgrade at your leisure, and run tests in CI with | the minimum version you want to support. If you're doing | something crazier that requires ABI compatibility between | separate builds (or you just want consistency), you can add a | `rust-toolchain` file that upgrades the compiler on dev | machines automatically, as seamlessly as Cargo downloads new | dependency versions. | burntsushi wrote: | To clarify a bit, the key thing here is that the OP is | maintaining their own patches to Rust's standard library. | While the API of std is itself backwards compatible, its | implementation uses a whole mess of unstable nightly | features. That means that std for Rust 1.x can't necessarily | be built with Rust 1.(x-1). EDIT: Nor can std for Rust | 1.(x-1) be necessarily built by Rust 1.x. | | It's true that you don't have to force every contributor to | upgrade every six weeks, but you do very likely need to have | every contributor use the same version of Rust. (Which can be | accomplished with a rust-toolchain file, as you mention.) | | The problem here is that if you don't do this upgrade | whenever a new Rust release is made, you're just putting off | that work to some other point. Maybe you do it every 12 weeks | instead of 6 weeks, that would probably be okay. But I'd | imagine waiting a year, for example, could be unpleasant. | ntoskrnl wrote: | > OP is maintaining their own patches to Rust's standard | library | | Oops, that's the bit I must have missed. That does sound | like an ordeal and I don't have an easy answer. | albrewer wrote: | This is one thing I struggle with when learning Rust. | | I want to have some examples of purely idiomatic Rust code | solving some bog-standard problems, that way I can copy what | that project's doing while I get comfortable enough with the | language and learn to make my own decisions. | Starlevel001 wrote: | > This is in part because all the Rust documentation is either | written in eli5 style (good luck figuring out "feature"s from | that example), or you're greeted with a formal syntax definition | (technically, everything you need to know to define a "feature" | is in there, but nowhere is it summarized in plain English), and | nothing in between. | | I wish I wish that Rust had a better documentation system. It's | rather telling that any serious project has to use an entirely | separate static site generator because the official doc system is | so crippled. | | Compare this to the Python docs, or some truly excellent Python | library docs (like Trio: https://trio.readthedocs.io/en/stable/, | or Flask: https://flask.palletsprojects.com/en/2.1.x/, or Django: | https://docs.djangoproject.com/en/4.0/https://docs.djangopro...), | which are all written using Sphinx and integrate properly with | crossrefs and such rather than writing manual markdown links as | an example. | pitaj wrote: | I don't find rustdoc lacking at all. It's great for API | documentation and it does have intradoc links. | | Of course for a more serialized tutorial, rustdoc is not a good | fit so we have mdbook. | est31 wrote: | intradoc links are great, and I disagree with GP that rust's | documentation tools are bad, they are pretty great. However, | intra doc links have the limitation that you can't link to | downstream crates: https://github.com/rust- | lang/rust/issues/74481 | veber-alex wrote: | You linked to docs of 3 python projects and each one looks | entirely different while the docs of all rust crates look | exactly the same. | mostlylurks wrote: | It is a good thing that the documentation for different | projects looks entirely different. I find that for me, it | makes it much easier to keep track of and remember everything | you're looking at if everything has a different aesthetic | anchoring it, both in working memory (if you're looking at | documentation for several projects simultaneously) and long- | term memory. | [deleted] | burntsushi wrote: | 'cargo doc' is absolutely one of my most favorite things about | Rust. I've never once seen it as crippled and I've never once | reached for an "entirely separate static site generator" to | write docs despite maintaining several serious projects. | | Writing out explicit links sucked, but we have intradoc links | now. It was a huge win. But my first paragraph above was true | even before intradoc links too. | | Also, I hate Sphinx. It's awesome that folks have been able to | use it to produce great docs, but I've never been successful in | using it. I disliked it enough that I wrote my own tool for | generating API documentation in Python.[1] | | [1]: https://github.com/mitmproxy/pdoc | yencabulator wrote: | I wish cargo doc's doctests for binaries worked. | | Internal APIs need loving too. | burntsushi wrote: | 'cargo doc' can produce docs for internal APIs too. On | mobile or I would link the docs. | yencabulator wrote: | https://github.com/rust-lang/rust/issues/50784 | epage wrote: | I find rustdoc lacking for clap. rustdoc does a good job with | API reference documentation and is improving in its handling | of examples but derive reference and tutorial documentation | are a weak point. | | For examples, its improving with the example scraping work | (e.g. https://docs.rs/clap/latest/clap/struct.ArgMatches.html | #meth...) but testing of example is still lacking. I've | written trycmd to help (https://github.com/assert-rs/trycmd). | | For derive reference and tutorial documentation, your choices | are | | - A very long, hard to navigate top-level documentation, see | https://docs.rs/structopt/latest/structopt/ | | - External documentation, see https://serde.rs/ | | - Dummy modules to store your documentation (I've seen this | used but can't remember one off the top of my head) | | For clap, my documentation examples are best served as | programs and we've had a problem with these being broken. The | Rust CLI book has a decent strategy for this by pulling in | code from external files (https://rust- | cli.github.io/book/index.html). I was tempted to do that for | clap where example code and output (all verified via trycmd) | are pulled into an mdbook site but I've stopped short and | just have a README that links out to everything | (https://github.com/clap- | rs/clap/blob/master/examples/tutoria...). Its not great. | burntsushi wrote: | > Dummy modules to store your documentation (I've seen this | used but can't remember one off the top of my head) | | Yeah I've done this and it works fantastic: | https://docs.rs/csv/latest/csv/tutorial/index.html | | All the examples are tested too. So not sure about the | problem there. | | Can't speak to 'derive' docs. I rarely use derives outside | of what std/serde give you, and I never publish any. | | But even so, I didn't say that rustdoc has zero weaknesses. | :-) I said it is one of my favorite things about Rust | because it is just so damn good. I've tried writing docs in | several other languages before and they are leagues behind | IMO. I would absolutely not call it "crippled." Not even | close. | farzatv wrote: | jvanderbot wrote: | I loved this perspective from a hardware oriented engineer coming | to appreciate the enormous complexity and difficulty in providing | a stable and useful data structures and algorithms library as | part of, say, rust std. | | Each complaint is valid, but some of it is (they admit) coming | from a bit of naivete. They're surprised red black trees are | included in the Linux kernel? why? They were surprised at how | useful rust std and a good? data structure foundation was? why? | alexfromapex wrote: | When Nightly is breaking no-std targets, is there not a way to | pin a specific Nightly release to prevent that? | vgel wrote: | There is, but then you're pinning yourself to whatever bugs are | in that nightly, and making the eventual upgrade that much | worse. | steveklabnik wrote: | There is, yes. You put a file in the root of your project with | the specific version of Rust you want, and it'll get picked up | and used by the tooling. | collaborative wrote: | I experimented with replacing an Express server with Rust while | keeping the same js syntax and still running on Node | | Granted this adds overhead, but my conclusion was that the | performance gain is not worth the effort. Sure, memory looks | almost flat but response times aren't that much better | | https://github.com/javieranton-zz/warp_like_express | lllr_finger wrote: | It's really cool that you experimented with this! | | My experience is that choosing Rust just for performance gains | usually doesn't pay off. In your case, node already uses C/C++ | under the hood, so some of what you're replacing could just be | switching that for Rust. | | The primary reason I reach for it is when I want the stability | provided by the type system and runtime, and to prevent a | litany of problems that impact other languages. If those | problems aren't something I'm looking to solve, I'll usually | reach for a different language. | curun1r wrote: | > choosing Rust just for performance gains usually doesn't | pay off | | Performance is a complex topic. Other languages can be fast | and you're likely right that with simple initial benchmarks, | Rust isn't going to out-perform other languages by enough to | make much of a difference. | | But what about consistency of performance? Is your | 1,752,974,468th response going to be as fast as the ones in | your benchmark? To me, that's been the eye opener of | deploying Rust in production. We saw P100 response times | within 10ms of P0. The absolute worst case was below the | threshold for human observability from the absolute best case | over many months of heavy use. The metrics graphs were | literal flat lines for months on end across tens of billions | of requests. I have never seen that in any garbage-collected | language. | | That kind of performance may not be necessary for your needs | and you may be able to tolerate or otherwise live with | occasional slowdowns. But there are plenty of cases where | consistent performance is necessary or extremely desirable. | And in those cases, it's nice to have Rust as an option. | dgan wrote: | > 100k LOC over two years | | Dude wrote more code per week than me in last 6 month at daily | job | sydthrowaway wrote: | Well, he quit Big Tech long ago, now actually builds things | instead of phoning it in. | sim7c00 wrote: | really interesting read, and nice to see people writing operating | systems on rust and have also plus points besides grievances. | particularly enjoyed you found rust sometimes spares you the | 'damn i need to rewrite this entire thing' tour that C always | hits me with :D. now i am more hopeful my re-write-the-entire- | thing-in-rust was an ok'ish choice. | bunnie wrote: | Took me a full year of questioning life choices before it felt | worth it, but fearless refactoring is _so nice_. I may have | trouble going back to C just for that. | cek wrote: | As I was reading the article (in which I learned a ton about | Rust, of which I know little), I kept thinking "I know that | guy!". | | Then I realized the OP was THE "Bunnie" of Xbox reverse | engineering fame [1]. <3 | | [1] https://en.wikipedia.org/wiki/Andrew_Huang_(hacker) | _wldu wrote: | Once rust stabilizes, I think it needs an ISO standard like C and | C++ have. I can't see automobile manufactures using rust without | one. One reason C and C++ are still widely used is due to this. | When we are writing code that is expected to run for decades, | having a corporate/community backed language is not sufficient. | We need global standards and versions that we can rely on decades | latter. | rwaksmunski wrote: | Lack of standards committee body making decisions is feature, | not a bug. Car manufactures can stick with C. | Avamander wrote: | Considering how "smart" cars are getting, no, they shouldn't. | pie_flavor wrote: | What has the standard actually gotten C and C++? Basic features | needed in every single code base like type punning on | structures are standardly UB, while design-by-committee results | in C++ feature hell. | | It doesn't get any harder to write a function exhibiting a bug | just because there's a standard saying the function shouldn't | have bugs in it. No matter what, you are trusting a compiler | vendor that the code it compiles and the functions it links | against don't have bugs. | | A standard is not a magic spell that creates better software | through its incantation; it provides for _multiple separate_ | compiler vendors to be able to compile the same code the same | way, which is a total fiction in C /C++, and not required for | languages like Python or Lua. I view it as nothing more than | the streetlight effect. | Avamander wrote: | > What has the standard actually gotten C and C++? | | As the person you replied to said, usage by other industries. | Replacement to MISRA C maybe even. | bregma wrote: | A part of the safety story of any useful toolchain compliant | to ISO 26262 as a SEOOC is that it verifiably implements the | language as documented in the standard. The "verifiably" part | is important. If there is no standard to verify against, how | do you know it's doing the right thing? | | The language standards themselves state outright that | programs containing undefined behaviour are malformed. If you | write malformed programs, you can not assume that they are | safe. Don't blame language standardization for your writing | bad, unsafe software if you're not going to follow it. | | In addition verifiably conformant compilers for translating | your programs into software, the standard allows other tools | to be written to perform things like static analysis, | complexity analysis, and conformance to other published | guidelines (eg. MISRA). These things are not possible where | the definition of the language is "whatever one single | toolchain vendor decides it will be this week". | KerrAvon wrote: | Prior to the C/C++ standardization process, every compiler | implemented a different dialect of those languages, and there | wasn't a complete and accurate specification for them. Some | very basic C code working with one compiler might not work on | another. | | I don't think Rust or any other modern language needs to be | standards-org standardized, but this is a different era; | there is a single solid, well-documented, versioned reference | implementation for Rust. That was never the case for C or | C++. | ModernMech wrote: | > Some very basic C code working with one compiler might | not work on another. | | I teach C and C++, and you have no idea how often I hear | "But it worked on my machine!" when I give back bad grades | due to code that segfaults when I go to run it. | ThatGeoGuy wrote: | Yeah I mean this is still kind of the case today, Rust just | avoids it because there is really only one reference | implementation. That may not even be true forever, Rust on | GCC is continuing to get more and more feature complete | over time. [1][2] | | Take the "defer" keyword in GNU C - it's valid in anything | that has the GNU extensions but isn't standard C at all. | And yet, some projects swear by it (it's not a bad feature, | just nonstandard). | | There's a lot of weirdness in C implementations even | looking across LLVM, GNU, or even when picking which libc | you want! Try porting any nontrivial project to work with | musl-libc. You might find that it's not as easy as swapping | in a target and building statically! | | This is perhaps the whole rub with standardization - it's | bought us as developers a lot, but it doesn't cover | everything. The veil was kind of lifted for me when I | started trying to use different Scheme implementations in a | "standardized" way. I eventually gave up on that and just | use whatever implementation I am most happy with (often | CHICKEN, but that's a digression). | | This gets more complicated with C++, which modern standards | mostly requires C11, but then also doesn't support | everything that C11 requires either. They're different | languages but yeah, compilers are gonna disagree on some of | the edges there. | | [1] https://github.com/Rust-GCC/gccrs | | [2] tangentially, Rust also avoids some UB discussion | because the type system is a bit more complete in terms of | its properties than C is, so they can resort to Option or | Result when things get dicey in an API. Further, there's no | official Rust ABI unlike C, so you don't have to worry | about that either... | scoutt wrote: | > No matter what, you are trusting a compiler vendor that the | code it compiles and the functions it links against don't | have bugs. | | I guess the key factor about a standard is that as a | corporation you can point fingers if something goes wrong | ("the compiler and/or the MISRA C checking tools you sold me | are not compliant with the standard because of this bug!"). | | Also the committee can point fingers back if required ("the | UB is clearly specified in the standard!"). | | If I were a team manager at a big automotive factory in | charge of the ECU system, I would go the private way, with | guarantees, and paying a lot of money. In case of failures, I | can point fingers and someone would answer the phone on the | other side if I complain. | | Who should I call or who should I point my finger at, if | something goes wrong because of a bug in Rust? A Github user | on the other side of the planet? | pie_flavor wrote: | If there were a standard, you'd still be pointing at | opposite-hemisphere github users. This is what I mean about | the streetlight effect - the standard has jack to do with | the outcome. If you are buying a product from a vendor, the | vendor is responsible for the product, and if you are using | an open-source community-managed product, it's much harder | to point fingers. The source of truth can be an ISO | standard, or it can be documentation, it doesn't matter. | shadowofneptune wrote: | C89 did: | | * FILE* was a big I/O abstraction that C did not have before. | With Unixes and MS-DOS there were file handles, but many | other platforms had nothing like that. | | * That there was a clear idea of what kind of operations were | well-defined was a pretty big deal. Remember, all there was | before was K&R to go off as a reference, or maybe you had | access to the Portable C Compiler. It was also a time where | you had a lot more oddball architectures. | | * void return types and parameters. There was no idea of a | procedure in early C, only functions with useless return | values. | | And of course more. There are definitely worse cases of ISO | standards than C and C++. Both are noticably better out of | it. | steveklabnik wrote: | The industry has already taken an interest in Rust; a lot of | things going on aren't public yet, but we've seen job openings, | and things like https://www.autosar.org/news- | events/details/autosar-investig... | | ISO Standards are not generally required. | https://news.ycombinator.com/item?id=28366670 | infamouscow wrote: | The US government has a very long history projecting it's | will on other countries. Under the guise of national | security, what is stopping the US government from changing | Rust to prevent it from working in Russia, Iran, or Canada? | The scenario is somewhat hyperbolic, but the US and European | centric nature of Rust gives people in less developed nations | pause. | vlang1dot0 wrote: | If the US gov decides to project its will on your software | project, an ISO standard is not going to help you at all. | They will sabotage the ISO process, or force your hosting | provider (GitHub) to remove your project or apply changes | to it, or just kidnap your maintainers and beat them with | wrenches until they comply[0]. | | If your threat model legitimately considers the US gov to | be a hostile actor, you need far more than a piece of paper | that claims what the behavior of your compiler is. | | [0]: https://xkcd.com/538/ | steveklabnik wrote: | How would one change a programming language to not work in | a country? | | Even assuming that is possible, the answer is the same as | any open source project: you'd have to convince the teams | to make that decision. Nothing special there. | KerrAvon wrote: | Why would the US government care about Rust? And what could | they possibly legislate to change it? Do you have a | plausible scenario in mind? | _wldu wrote: | They care deeply about software security and memory flaws | (everyone should). If rust had an ISO standard, then it | could be used in more sensitive military and aerospace | systems. | | https://www.stroustrup.com/JSF-AV-rules.pdf | | Also, when something is an ISO standard, then governments | can't legislate that some countries may not be allowed to | use it. | | https://help.duo.com/s/article/7544?language=en_US | xxpor wrote: | Something being an ISO standard has nothing to do with | being able to send OFAC after you? Fundamentally the | difference is providing a service vs an idea just | existing in the ether. You can't sanction Rust, it's just | an idea. You _could_ tell rustup they can 't allow | downloads from IPs that match sanctioned countries. | steveklabnik wrote: | A senator^Wcongressman asked some questions about Rust | and its nightly toolchain whenever Facebook's | cryptocurrency was under scrutiny by regulators. A French | government agency has a whole set of coding guidelines | for Rust. The government of Quatar was using Rust before | 1.0; haven't heard much since, but I assume they're still | using it. A New Zealand firefighter company was using | some Rust. | | Programming languages are tools. Governments use tools. | It shouldn't be surprising that they may have an | interest. | | That said I find your parent comment also a bit silly for | the other reasons you state. | unrealhoang wrote: | How to change an opensource programming language to prevent | it from working in a particular country? | | > The scenario is somewhat hyperbolic, but the US and | European centric nature of Rust gives people in less | developed nations pause. | | This point is correct with every semi-major programming | languages (top 100 popular?), so I don't think it's just a | Rust problem. | bogeholm wrote: | > what is stopping the US government from changing Rust to | prevent it from working in Russia, Iran, or Canada? | | Well, for one Rust is open source, so you could download | the source code and comment out the country ban yourself? | avgcorrection wrote: | I think C caught on because it spread like a cancer through | institutions like universities. | | Want to catch on? Be a virus. Not some gosh-darned | international standard. | wiz21c wrote: | FTA : "This is the point at which Rust's very strict typing and | borrow checker converts from a productivity liability into a | productivity asset." | | that's what rust is about in my own experience. Especially with | threads. | epage wrote: | I remember someone saying that "Rust skipped leg day", feeling | that Rust was overly focused on the borrow checker while only | solving a small number of problems. | | 1. I think its easy, especially for GC users, to forget that | memory management is really about resource management. | | 2. The composability of features with the borrow checker is | outstanding, like proper session types / locks or Send+Sync for | safe use data with threads. | ModernMech wrote: | Me too. A lot of people who try Rust encounter a very steep | learning curve, and tend to question whether the borrow checker | and strict typing is even worth it. For me, it's allowed me to | build larger threaded and distributed systems than I've ever | been able to before. I've tried to build such systems in C/C++ | but I've never been able to make something that isn't | incredibly brittle, and I've been writing in those languages | for 25 years. For a long time I thought maybe I'm just a bad | programmer. | | Rust changed all that. I'm kind of a bad programmer I guess, | because Rust caught a lot of bad decisions I was making | architecturally, and forced me to rewrite things to conform to | the borrow checker. | | This is the point at which I've found many people give up Rust. | They say to themselves "This is awful, I've written my program | one way I'm used to, and now it looks like I have to completely | rewrite it to make this stupid borrow checker happy. If I had | written in C++ I'd be done by now!" But will you really be | done? Because I had the same attitude and every time I went | back to C++ I surely built something, but if it got too large | it would be a sandcastle that would fall over at the slightest | breeze. With Rust I feel like I'm making skyscrapers that could | withstand an earthquake, and I actually am because the programs | I've written have weathered some storms that would have washed | my C++ code out to sea. | | Of course one can make stable, secure, performant systems in | C++ and many other languages. But apparently _I_ can 't, and I | need something like Rust to empower me. Someone else here said | that Rust attracts people who want to feel powerful and smart | by writing complicated code, but I like to write Rust code just | to not feel inept! | ReactiveJelly wrote: | > I wrote a small tool called `crate-scraper` which downloads the | source package for every source specified in our Cargo.toml file, | and stores them locally so we can have a snapshot of the code | used to build a Xous release. | | I thought `cargo vendor` already did this? | | https://doc.rust-lang.org/cargo/commands/cargo-vendor.html | | > This cargo subcommand will vendor all crates.io and git | dependencies for a project into the specified directory at | <path>. After this command completes the vendor directory | specified by <path> will contain all remote sources from | dependencies specified. | | Maybe he doesn't want to depend on Cargo. Fair enough, it's a big | program. | bunnie wrote: | The big thing I wanted was the summary of all the build.rs | files concatenated together so I wasn't spending lots of time | grepping and searching for them (and possibly missing one). | | The script isn't that complicated... it actually uses an | existing tool, cargo-download, to obtain the crates, and then a | simple Python script searches for all the build.rs files and | concatenation them into a builds.rs mega file. | | The other reason to give the tool its own repo is crate-scraper | actually commits the crates back into git so we have a publicly | accessible log of all the crates used in a given release by the | actual build machine (in case the attack involved swapping out | a crate version, but only for certain build environments, as a | highly targeted supply chain attack is less likely to be | noticed right away). | | It's more about leaving a public trail of breadcrumbs we can | use to do forensics to try and pinpoint an attack in | retrospect, and making it very public so that any attacker who | cares about discretion or deniability has deal with this in | their counter-threat model. | epage wrote: | Don't forget about proc macros. | | If they don't, I wonder if one of the auditing commands | should support drawing attention to build.rs and proc macros | like this. | rcxdude wrote: | I often wonder about what priorities lead to the kind of | focus on the build system as a supply chain attack vector. It | seems unusual that you are in a position where you have a | chunk of code you want to build and have to trust the system | that builds it but not the code, especially in a situation | where such concerns can't be adequately addressed through | sandboxing the build system. Personally if I was concerned | about the supply chain I wouldn't worry about 5.6k lines of | rust code running during the build and more the >200k | (extremely conservative estimate) lines running on the actual | system. (not that you can ignore the build system since of | course it can inject code into the build, just that it's such | a small part of the workload of reviewing the dependencies it | shouldn't really be worth mentioning). | klysm wrote: | This also confused me a lot. I'm not sure I understand the | threat model... | dimgl wrote: | > This is a superficial complaint, but I found Rust syntax to be | dense, heavy, and difficult to read. | | > Rust Is Powerful, but It Is Not Simple | | This is exactly why I haven't gotten into Rust. | klysm wrote: | What do you use instead? | secondcoming wrote: | This was a very interesting read. | | IMO the author underplays the visual ugliness of some Rust code. | Programmers tend to look at code for hours a day for years, and | so it should not be visually taxing to read and parse. This is | why syntax highlighting exists, after all. | | But the gist I got from it is that Rust is really a very good | static analyser. | gary17the wrote: | > This is a superficial complaint, but I found Rust syntax to be | dense, heavy, and difficult to read | | :) | | If you think that Rust is dense and difficult to eyeball, please | do try... Swift - purely for therapeutic reasons. But not the | usual, trivial, educational-sample, evangelism-slideshow Swift, | please, but real-world, advanced Swift with generics. All the | unique language constructs to memorize, all the redundant | syntactic sugar variations to recognize, all the special-purpose | language features to understand, all the inconsistent keyword | placement variations to observe, all the inferred complex types | to foresee, etc. will make you suddenly want to quit being a | programming linguist and instead become a nature-hugging florist | and/or run back to Go, Python, or even friggin' LOGO. I'm tellin' | ya. And, when considering Swift, we're not even talking about a | systems programming language usable with, say, lightweight | wearable hardware devices, but about a frankenstein created | (almost) exclusively for writing GUIs on mobile devices usually | more powerful than desktop workstations of yesteryear :). | | Rust is complex, but very good. | pphysch wrote: | Interesting, I had no idea what I was missing out on. | | Conversation from last week: | | Me: "So what are you working on at $company?" | | Friend: "We're building a complete HVAC management system for | all types of buildings, from hardware to software" | | Me: "Cool! What technologies are you building it on?" | | Friend: "Swift" | | Me: "...for like an iOS app to monitor the system?" | | Friend: "No, everything is written in Swift. The entire backend | too." | | Me: "Interesting... Have you shipped anything yet?" | | Friend: "No but the founder is running a prototype in his house | and we just secured another round of funding..." | | ** | | Is this a common thing? | gary17the wrote: | Considering the speed of adoption of server-side Swift as | well as the progress of Swift's support for Linux, I am | guessing we are talking about some expert variation of the | pump-and-dump investment technique here ;). | [deleted] | bfrog wrote: | Very cool, and it's true Rust is dense. On the other hand C, the | other typical option, either requires massive amounts of | ancillary tooling and macros like Zephyr to get even close to | doing as much at compile time. Those tools and macros add density | and complexity. Arguably C++ is about equivalent with fewer pros | over C and plenty of the cons of C still there along with some | new ones. | | I appreciate the idea of trying to create a auditable OS for an | MMU capable CPU, the reality is once you have feature you care | about that becomes harder and harder it seems. | jacquesm wrote: | Absolute gold this article. | | "In the long term, the philosophy behind Xous is that eventually | it should "get good enough", at which point we should stop | futzing with it." | | I wished more people would get this. | lodovic wrote: | You do need a very patient sponsor for such projects though | StillBored wrote: | I'm not sure I understand what you mean here. If anything a | sponsor should be happy if there is an end goal. Far to many | projects feel the need to constantly futz with their product | long past when its "done". I think the most people understand | this about windows. No one is asking for yet another UI | change, or intrusive snooping. Windows could have been done | the day they released 64-bit windows XP (or windows7 | depending on your politics), and we would have a far better | OS, if they had simply laid off 90% of the team leaving the | remaining people in a bug fix only maintenance mode. | throwaway17_17 wrote: | 'Before [const generic], Rust had no native ability to deal with | arrays bigger than 32 elements'. | | Is this a correct statement? I have seen posts talking about | const generics being a new thing as of 2022. Did Rust actually | lack the ability to have an array with more than 32 elements? I | find it hard to believe that there was no way to have an array of | longer length and Rust still being a production level language. | jhugo wrote: | Since nobody else mentioned it, it's worth pointing out that | what e.g. JS calls an array is Vec in Rust and can be as long | as you want, with no ergonomic difference regardless of the | length. | | Array in Rust specifically refers to an array whose length is | known at compile time, i.e. a bunch of values concatenated on | the stack, and that's what the limitations applied to. | | The quoted statement pissed me off a bit (I otherwise enjoyed | the article) because it seems intended to mislead. The author | should have known the colloquial meaning of "array", and "no | ability to deal with" is factually incorrect. | dhosek wrote: | But see other comments--it wasn't an array limitation but | rather a trait limitation. | jhugo wrote: | Yes, I know, but the trait limitation only applies to | arrays, not to Vec. Many people coming from other languages | would reach for Vec first when they want an "array". I | believe that misunderstanding the meaning of "array" is why | GP was surprised that Rust couldn't (ergonomically) handle | more than 32 elements in an "array". | dhosek wrote: | Perhaps. But in writing an OS, sometimes you genuinely | _do_ want the guarantees of an array. You especially | would want to avoid the overhead that might come when the | Vec gets resized. | jhugo wrote: | Yes, and if you don't need dynamic size you can use an | array (of any size). The lack of trait implementations is | generally a minor inconvenience in the scale of the | various inconveniences of writing an OS. It doesn't stop | you doing anything. | bunnie wrote: | For the first year we did not have Vec because we were | no-std + stable so we literally had to use arrays and | could not reach out for heap allocated Vecs. | | Things got much better after we got std and could use | Vec, as you note, but there are still a few locations | where we have no choice but to use arrays (ie some crypto | APIs that are too risky to redesign, the boot loader, and | micro kernel itself which is still no-std come to mind | immediately). | carry_bit wrote: | You could have bigger arrays, what was missing were the trait | implementations. Originally the traits were implemented using a | macro, and the macro only generated implementations for up to | length 32. | Animats wrote: | There were some awful hacks to make integer parameters to | generics sort of work before "const generic" went in. There | were tables of named values for 0..32, then useful numbers such | as 64, 128, 256, etc. Those haven't all been cleaned out yet. | masklinn wrote: | It's not quite correct no. | | Before const generics most traits were only implemented up to | 32 elements though, which could be quite annoying. Even more so | as the compilation error was not exactly informative. | est31 wrote: | You have always been allowed to have arrays longer than 32 | elements, but _dealing_ with them used to be hard. Beyond the | Copy trait, which is a compiler builtin, many traits weren 't | implemented for arrays with more than 32 elements. | | The first such change was implemented in 1.47.0 in 2020 where a | bunch of traits were made work on all array sizes: | https://github.com/rust-lang/rust/blob/master/RELEASES.md#ve... | | It took a few releases, until 1.51.0 in 2021, until custom | traits could be implemented for arrays of any length: | https://github.com/rust-lang/rust/blob/master/RELEASES.md#ve... | | And the feature is still limited. For example, legacy users | like serde still can't switch to the new const generics based | approach, because of the same issue that the Default trait is | facing. Both traits could be using const generics, if they were | allowed to break their API, but neither want to, so they are | waiting for improvements that allow them to switch without | doing a hard API break. | daviddever23box wrote: | Nicely balanced article. | alkonaut wrote: | > "Hi, run this shell script from a random server on your | machine." | | You shouldn't run scripts from a random server but you probably | have to consider running scripts from a server you trust. If you | don't trust the server you run the script from, are you really | going to run the executables this script installs? If we ignore | the idea of downloading and building every program from source, | then you'll download and run programs compiled by someone else. | And you need to trust them, or sandbox the programs. There are no | alternatives. | | Yes, the bash script or msi can kill your dog and eat your | homework but there isn't much we can do about that without | running things in in sandboxes - and the (old/normal) windows app | model doesn't have that. | | Auditing the script won't help you, because it'll say it will | install a program somewhere. Which is what you want, so you'll | consider the audit "ok". But the people who wrote the | script/installer are the same people that created the program (or | have compromised the computers producing both) and now you'll run | the rustc.exe program you just installed and _that_ will eat your | homework! | | To most people there is no difference in how transparent a bash | script is compared to an msi. Downloading an msi from a https | server I trust, signed with a cert I trust, is something I'm | mostly comfortable with. The same applies to running a bash | script from a location that is trustworthy. | samatman wrote: | This is threat modeling. Bunnie Huang's threat model for | Precusor is considerably more stringent than the ordinary, to | put it mildly. | | Compare this to a C program where love it and hate, it's just a | bunch of files that get included by concatenation. There's no | magic to make your life easier or get you in trouble, | everything is done via manual transmission. | | The article goes into why they haven't been able to apply this | approach to Rust, even though they would like to. | usrn wrote: | With the other languages the apps on my machine are built with | (C, and to a large degree Python) I have the benefit of the | distribution maintainers at least looking in the general | direction of the source for things I install (including | development libraries.) Tools like Cargo shortcut that and open | me up to a lot of nastiness. It's very similar to the problem | on Windows really and I wouldn't be surprised if you started | seeing malware disturbed that way like we're currently seeing | on NPM and Pypi. | pornel wrote: | rustup in particular is well-behaved. It installs itself in a | single directory, without modifying the system, apart from | PATH which it warns you about, lets you skip it, and when it | does it, it does with care. | | OTOH many distros don't take care to build and package Rust | properly. For example, Rust patches its version of LLVM to | avoid known bugs. The particular combination of Rust version | + LLVM version is most tested. Distros that insist on | unbundling build Rust with a stock LLVM that doesn't have | these bugfixes, and often is an older version of LLVM that | hasn't been thoroughly tested with Rust. | | Then there's the mismatch of upgrade approach between the | Rust project and most distros. Rust uses an "evergreen" | (Chrome-like) approach to upgrades, in which the focus is on | making upgrades seamless and not breaking anything so that | they can be small and frequent. Most distros prefer | infrequent big upgrades, so they package unusably old and | officially unmaintained versions of Rust for no good reason. | kbenson wrote: | To me, the problem has never been that you're running a shell | script from some remote source, but that you're expected to | pipe it directly into an interpreter so the existence of what | you actually ran is ephemeral. | | There are the various levels of trust that you need to account | for, but as you and others bite, that isn't specifically | different to most people than some installer. | | What _is_ different is that there 's no record of what you ran | if you pipe it to an interpreter. If, later, you want to | compare the current script available against what you ran, | there's no easy way. | xigoi wrote: | Nothing prevents you from doing curl > | install.sh less install.sh sh install.sh | kbenson wrote: | Yes, that's the point. You can, and probably should do | that, but the guides don't bother with what is essentially | making one command two because two commands is one more for | someone to screw up. | | I think the trade off they are taking is fundamentally a | bad one with respect to security and accountability. It's | not even about checking the script ahead of time. It's | about checking what was actually run at a later date to see | what happened. If the script is never stored to disk, | determining whether a short lived hack of the script source | affected you is much harder. | Datenstrom wrote: | It always comes back to trusting trust [1]. | | [1]: | https://www.cs.cmu.edu/~rdriley/487/papers/Thompson_1984_Ref... | Quekid5 wrote: | And the response to that: https://dwheeler.com/trusting- | trust/ | amalcon wrote: | Auditing the script can certainly help, just not against | malice. E.g. if the script is not set up in such a way that it | protects against partial execution, then this represents a kind | of vulnerability (truncation) that signed MSI/.deb/etc files | simply do not, by the design of the file format. | | Yes, it's possible (even easy) to write a curlbash script that | doesn't have this issue (or the various other issues). | Reviewing the script still buys you _something_. | [deleted] | Confiks wrote: | > Auditing the script won't help you, because it'll say it will | install a program somewhere. Which is what you want, so you'll | consider the audit "ok" [but that program is made by the same | people as the installation script]. | | Your argument doesn't take into consideration that build | artifacts / software releases have culture and best practices | behind them. Such releases are often considered, tested, cut, | digested, signed and included in package managers delegating | trust. | | Many one-off installation shell scripts are not afforded that | culture, especially when maintained from within (static) | websites that update frequently. On the other hand, they are | small enough for you to audit a bit. If you'd compare the | script with one that someone else downloaded a month earlier | (i.e. archive.org), that would help a lot to establish trust. | | > If we ignore the idea of downloading and building every | program from source | | Your argument is equally valid when building every program from | source. You will not be able to review the source code of | moderately large programs. You will need to delegate your trust | in that case as well. | beardicus wrote: | bunnie is so kind and thoughtful, even when being critical. | compare this to the typical frothy-mouthed 'rant' format we see | here. | | i'm sure rants are cathartic for the writer, but i rarely find | them compelling. | jacquesm wrote: | Not only that, he's modest. | rob74 wrote: | Well, that's the difference between the "I like [X], but have a | few complaints that I want to get off my chest" kind of rant | and the "I hate [X], and want to convince everyone how bad it | is and to never ever use it again" kind of rant... | StillBored wrote: | " Yes, it is my fault for not being smart enough to parse the | language's syntax, but also, I do have other things to do with my | life, like build hardware." | | and "Rust Is Powerful, but It Is Not Simple" | | among all the other points, should be enough to disqualify it for | mainstream use. The core of most arguments against C++ boil down | to those two points too. If a large percentage of the engineers | working in the language have a problem understanding it, they are | going to have a hard time proving that their aren't any | unexpected side effects. Of which both C++ and rust seems to be | full of, given the recent bug reports in rust and projects people | are using it in. | | So, I'm still firmly in the camp that while there are better | system programming languages than C, rust isn't one of them (hell | even Pascal is probably better, at least it has length checked | strings). | IshKebab wrote: | > The core of most arguments against C++ boil down to those two | points too. If a large percentage of the engineers working in | the language have a problem understanding it, they are going to | have a hard time proving that their aren't any unexpected side | effects. | | That's true for C++ but not for Rust, because Rust will _tell_ | you if there 's some kind of unexpected behaviour that you | didn't think about, whereas C++ will allow UB or whatever | without telling you. | | That's the big difference between (safe) Rust's complexity and | C++'s complexity. They are both very complex, but in Rust it | doesn't matter _too_ much if you don 't memorise the complexity | (complicated lifetime rules, etc.) because it will just result | in a compile error. Whereas in C++ you have to remember the | rule of 3... no 5... etc. (that's a really simple example; | don't think "I know the rule of 5; C++ is easy!"). | klysm wrote: | > among all the other points, should be enough to disqualify it | for mainstream use. The core of most arguments against C++ boil | down to those two points too. | | Nope not at all, that's not a valid comparison. | | I argue that there is no simple solution that affords what rust | does. Engineers have to use their heads to write correct and | fast software. I'm so tired of people just accepting lack of | memory safety because it's "hard" to do correctly. There are | real consequences to the amount of insecure trash that exists | because of this mindset. | masklinn wrote: | > The core of most arguments against C++ boil down to those two | points too. | | No, the core arguments against C++ boil down to it not | providing enough value for these costs, and that its | complexities are not orthogonal and interact sub-optimally with | one another so the complexities compound superlinearly. | StillBored wrote: | Which completely misses how people use C++ as a systems | programming language. For the most part those users treat it | like a better C, only reaching for C++ features when its an | overwhelming advantage over C and generally banning | significant parts of the language. | | See arudino for one example. | avgcorrection wrote: | You've painted yourself in a corner considering your | argument against Rust was its complexity. | Animats wrote: | The basic problem with C++ is that it has hiding without | memory safety. | | C has neither hiding nor memory safety. Most newer languages | have both. C++ stands alone as a widely used language with | high level unsafe abstractions. This is the source of most | buffer overflow security advisories. | sophacles wrote: | In that case we need to disqualify: Linux, threading, | networking, anything graphical, anything involving a database, | anything that has the ability to write memory that is read by | other lines of code, and probably any computer that allows | input and/or output just to be safe. | StillBored wrote: | I guess my point isn't really clear. Its more a case, of your | just swapping one set of problems for another. People | shouldn't avoid hard problems, but they should be seeking to | solve them with better tools, not ones that just translate | the problem domain without providing a clear advantage. | | In the grand scheme your looking for the optimal intersection | of simple/expressive/performant/safe and rust seems to fail | on the simple/expressive axis vs just simple C which people | chose over languages like C++ which are more expressive | because that expressiveness is a source of bugs. And on the | safety side, rust fails miserably when compared with more | fully managed environments. So, it becomes a question of | whether that additional cost provides much vs just spending | more putting guardrails around C/C++/etc with more formal | methods/verifiers. | athrowaway3z wrote: | > And on the safety side, rust fails miserably when | compared with more fully managed environments. | | That's a rather extreme, unsubstantiated, and imo false, | claim to just throw out there as a matter of fact. | | And I'd also be curious how you can square putting enough | formal methods/verifiers around C/C++ without creating a | far worse entry into the simple/expressive axis than rust. | avgcorrection wrote: | > a question of whether that additional cost provides much | vs just spending more putting guardrails around C/C++/etc | with more formal methods/verifiers. | | So the conclusion (or the closest you get to proposing an | alternative strategy) is to just to pour more tens of | millions down the black hole called Cartographing The Wild | West of Pointers. Hardly pragmatic. | lawn wrote: | C++ is one of the most used languages, and it does seem to me | that Rust has enough momentum going for it to be a commonly | used system programming language as well. | | I do agree with his points, but I don't think it's enough to | disqualify it for mainstream use. | nu11ptr wrote: | > This is a superficial complaint, but I found Rust syntax to be | dense, heavy, and difficult to read | | I'm a huge Rust fan, but sort of agree. First, I dislike C-style | syntax in general and find it all very noisy with lots of | unnecessary symbols. Second, while I love traits, when you have a | trait heavy type all those impl blocks start adding up giving you | lots of boilerplate and often not much substance (esp. with all | the where clauses on each block). Add in generics and it is often | hard to see what is trying to be achieved. | | That said, I've mostly reached the conclusion that much of this | is unavoidable. Systems languages need to have lots of detail you | just don't need in higher level languages like Haskell or Python, | and trait impls on arbitrary types after the fact is very | powerful and not something I would want to give up. I've even | done some prototyping of what alternative syntaxes might look | like and they aren't much improvement. There is just a lot of | data that is needed by the compiler. | | In summary, Rust syntax is noisy and excessive, but I'm not | convinced much could have been done about it. | SemanticStrengh wrote: | What kind of meaningful data is passed (besides lifetimes) that | isn't passed in Kotlin or scala 3 extension methods? | masklinn wrote: | Ah yes, "what kind of meaningful data is passed besides the | most important concept in the language?" | | Also, the ownership mode, a concept entirely missing from | Kotlin or Scala. | | As GP says, Rust's syntax is pretty noisy, but much of the | noise is answers to questions _other languages don 't even | ask_. | | And many complains are requests for additional noise for | things which are just regular in Rust, like additional | syntactic sugar for Option and Result. | Animats wrote: | The main Rust syntax is OK, but as the author points out, | macros are a mess. | | The "cfg" directive is closer to the syntax used in ".toml" | files than to Rust itself, because some of the same | configuration info appears in both places. The author is doing | something with non-portable cross platform code, and apparently | needs more configuration dependencies than most. | logicchains wrote: | >That said, I've mostly reached the conclusion that much of | this is unavoidable. Systems languages need to have lots of | detail you just don't need in higher level languages like | Haskell or Python, and trait impls on arbitrary types after the | fact is very powerful and not something I would want to give | up. | | Have you checked out C++20 concepts? It supports aliases and | doesn't require explicit trait instantiations, making it | possible to right such generic code with much less boilerplate. | loeg wrote: | My experience in C++ prior to 20 is that it is a lot more | verbose/boilerplatey than Rust. I'd love to see that get | better, but I think C++ is starting from significantly | behind. | jcelerier wrote: | C++17: template<typename T, | std::enable_if_t<std::is_floating_point_v<T>, int>* = | nullptr> void func(T fp) { ... } | | C++20: void func(std::floating_point auto | fp) { ... } | Frizi wrote: | There is an equivalent syntax in Rust to both of those | examples, and in both cases I find it less verbose. The | template variant is roughly equivalent to: | fn func<T: FloatingPoint>(fp: T) { ... } | | And the "auto" variant is similar to impl argument in | Rust: fn func(fp: impl FloatingPoint) { | ... } | jcelerier wrote: | I really don't see in which way the second case is less | verbose especially if you add a non-void return type, | e.g. i32. The first case would also be doable like this, | which is pretty munch the exact same than your first | example with the added "template" keyword | template<std::floating_point T> void func(T t) { | ... } | | (also, it's not really equivalent - if I'm not mistaken | with traits you can only use what the trait declares ; in | C++ you can for instance do something like | template<typename T> concept CanBlah = requires | (T t) { t.blah(); }; | | and still be able to do void | func(CanBlah auto t) { log << "func:" << t; | t.blah(); } | | instead of polluting the prototype with all possible side | concerns) | ducktective wrote: | > I found Rust syntax to be dense, heavy, and difficult to read | | Reminds me of this section of Rich Hickey talk: | https://www.youtube.com/watch?v=aSEQfqNYNAc | voorwerpjes wrote: | There are similar issues in Rust to the one Hickey talks | about in Java, in terms of cognitive overload and difficulty | in a human parsing the program. However, I've found rust | largely avoids issues with a bunch of different classes and | with their own specific interfaces with a bunch of getters | and setters in the HTTP servlet example because of Trait | interface reuse. | fulafel wrote: | From the modern systems programming languages set, Go does | better in this respect. But admittedly it doesn't reach to | quite as low in fitness for low level programming as Rust. | weatherlight wrote: | Go is a systems programming language? | pjmlp wrote: | Depends if one considers compilers, linkers, networking | stacks, kernel emulation, unikernels, userspace drivers, | databases, GPGPU debugging systems programming or not. | | Despite my opinion on Go's design, I rather would like to | see people using Go instead of C for such use cases. | tptacek wrote: | Yes. The only people for whom this is controversial are | message board nerds. The actual language designers don't | have much trouble over the concept. Here's a link to the | designers of Rust, C++, Go, and D on a panel having little | problem working through the nuances: | | https://news.ycombinator.com/item?id=31227986 | | This perpetual debate reminds me of the trouble HN used to | have with the concepts of "contractors" and "consultants", | where any time someone mentioned that they were doing | consulting work there'd be an argument about whether it was | in fact contracting. It's a message board tic, is what I'm | saying, not a real semantic concern. | monocasa wrote: | To be fair, that first question about 'what is a systems | programming language' is answered by Rob Pike then Andrei | Alexandrescu as | | Pike: When we first announced Go we called it a systems | programming language, and I slightly regret that because | a lot of people assumed that meant it was an operating | systems writing language. And what we should have called | it was a 'server writing language', which is what we | really thought of it as. As I said in the talk before and | the questions, it's turned out to be more generally | useful than that. But know what I understand is that what | we have is a cloud infrastructure language because what | we used to call servers are now called cloud | infrastructure. And so another definition of systems | programming is stuff that runs in the cloud. | | Alexandrescu: I'm really glad I let Rob speak right now | because my first question was 'go introduces itself as a | systems programming language' and then that disappeared | from the website. What's the deal with that? So he was | way ahead of me by preempting that possible question. | | So it seems to me that they struggle with the nuances of | the concept as much as the commenters here, particularly | as it pertains to Golang. | fulafel wrote: | Yes, as it's used for that a lot. Eg many databases | (CockroachDB, Prometheus, InfluxDB, dgraph etc), gVisor, | Kubernetes, Fuchsia, etcd, and so on. And also in the | origin story it was aiming to compete with C++ for many use | cases IIRC. | mindcrime wrote: | That's tricky to answer, because it depends a lot on what | you count as "system software". If you mean literally "the | operating system", then arguably not. But if you include | middleware, databases and other "infrastructure" stuff, | then arguably yes. | johndoe0815 wrote: | Go has been used to implement OS kernel code, e.g. in the | Biscuit OS from MIT: https://github.com/mit-pdos/biscuit | | Of course, the garbage collector did not exactly make it | easier - but it's an interesting piece of software. | mindcrime wrote: | _Go has been used to implement OS kernel code,_ | | _but it 's an interesting piece of software._ | | Agreed. And I didn't mean to imply that it's _impossible_ | to use Go that way, but I think it 's fair to say that | it's less common and perhaps even less desirable to do | that. | | OTOH, people have written (at least parts of) Operating | Systems in Java[1] even, so never say never... | | [1]: https://github.com/jnode/jnode | jandrewrogers wrote: | A proper database can be implemented in python -- I've | done it -- but that doesn't make it a systems language. A | "systems language" comes with the strong implication that | it is possible to write an implementation of most | software that is competitive with the state-of-the-art in | terms of performance, efficiency, and/or scalability. | That is only possible in languages like C, C++, Rust, and | similar, hence the "systems language" tag. | | Languages that are not systems language trade-off this | capability for other benefits like concise expressiveness | and ease of use. | UnpossibleJim wrote: | It _can_ be, but I wouldn 't recommend it personally: | | https://golangdocs.com/system-programming-in-go-1 | | EDIT: formatting | veber-alex wrote: | Go is not a systems programming language. | | I also personally find Go syntax to be horrible, especially | now with generics. | pjmlp wrote: | Depends if one considers compilers, linkers, networking | stacks, kernel emulation, unikernels, userspace drivers, | databases, GPGPU debugging systems programming or not. | | I personally consider better use Go than C for such | purposes, even if they aren't "systems programming". | Thaxll wrote: | The Go syntax is fine and easy to read, you don't need to | know Go to undertsand what the code is doing, can't say the | same for Rust. | ohCh6zos wrote: | I think this is a matter of opinion not fact. I have | worked as a Go programmer for three separate companies | and it may be the least readable, least understandable | language I have encountered. | Thaxll wrote: | Well it's hard to argue against a language with 25 | keywords. | jerf wrote: | Oh, not even close. It does what most languages do and just | elides, ignores, or hard-codes the answers to all the | questions Rust has. That's _a_ solution, sure, a very valid | one chosen by many languages over many decades, but certainly | not "much better". We absolutely need at least one language | that doesn't hide all that and I think the programming | language community as a whole will really benefit from the | list of choices for that being expanded from "C++", which is | getting _really_ long in the tooth And I 'm not even sure C++ | was ever really _designed_ to be this language, I think a lot | of it just sort of happened by default and it sort of backed | into this role, and frankly, it shows. Rust being _designed_ | for this can 't hardly help but be nicer, even if we | completely ripped out the borrow checker aspect. | codegeek wrote: | I wanted to learn Go while working professionally with PHP and | Python. I loved the simplicity and syntax of Go overall. I | learned Go enough to build a small internal tool for our team | and it is Production ready (at least internally). Then I wanted | to learn Rust since it is so popular and always compared with | Go and the syntax made me lose interest. Rust may be amazing | and I will be more open minded to try later but it didn't spark | the interest. Superficial I know since the real power is in | functionality etc but just an anecdote from an amateur. | skrtskrt wrote: | Another point is just about the maturity of language and | libraries. | | I started learning Rust recently and when searching how to do | some pretty basic stuff, the answers are like "well you used | to do this but now you do this and soon you'll be able to do | this but it's not stabilized" | | I figure I'll just check back in 5 years, I don't have the | time or patience to be on the bleeding edge when I'm trying | to get things done. | codegeek wrote: | Good point. In software especially web world, I am usually | wary of tech that is not at least 10 years mature/old. | worik wrote: | Yes. Go is better unless you need the features of Rust. | sph wrote: | There's definitely a space for native languages that are not as | dense and performant possibly as Rust. I will trade some | readability when I need strict memory guarantees and use Rust, | but most of my time I'd like to use something readable and fun | to use, which Rust ain't. | | I used to use Go, not much of a fan anymore, but I'm liking | Crystal a lot to fill this space. Eventually Zig when it's more | mature. | sbmthakur wrote: | Just started learning Go. If I may ask, why did you loose | interest in Go? | sph wrote: | Not enough syntax sugar, not functional enough, and a few | smaller papercuts. | | It feels dry, like a humourless android. Not very fun to | write but probably the most pragmatic choice for the | problem. I prefer having fun when I program. | amelius wrote: | > Systems languages need to have lots of detail you just don't | need in higher level languages like Haskell or Python | | True, but Rust is being used for a lot more than just system | programming, judging from all the "{ARBITRARY_PROGRAM} written | in Rust" posts here on HN. | hawski wrote: | I find that Rust tends to have code that goes sideways more | than downward. I prefer the latter and most C code bases, that | I find elegant are like that. | | It is like that, because of all the chaining that one can do. | It is also just a feeling. | est31 wrote: | There are two upcoming features, let chains and let else, to | counter the sideways drift. | | Sometimes it's also the formatter though that outputs | intensely sideways drifting code: https://github.com/rust- | lang/rust/blob/1.60.0/compiler/rustc... | UmbertoNoEco wrote: | est31 wrote: | While generally, yes, features are bloating up a | language, one could argue these two particular features | _reduce_ complexity. Like why am I forbidden to use && | in a if let? And why does _if let_ support both | irrefutable and refutable patterns but deconstructing | _let_ requires them to be irrefutable? | UmbertoNoEco wrote: | There is surely some "law" in some place of the internet | that says something like: "Every programming language | valid construction no matter how ugly, | obscure,verbose,old,etc will find its way to lots of | codebases". See C++. | estebank wrote: | Yes, John Carmack has said as much, at least in the | context of syntactically and semantically valid | constructs that are actually bugs making it into | codebases. What does that have to do with let chains and | let else? | UmbertoNoEco wrote: | The problem are not the new traits per se. The problem is | that the complexity of a language grows super-linearly | with the number of things added to it. There is beauty | (and productivity) in simplicity. When you need to do 2 | things and there are 2 ways of doing each, now you have 4 | different combinations. All languages are more or less | guilty of this (even those which promise "Just 1 way to | do things") but it is undeniable that Rust is joining C++ | in the right side of the complexity Bell curve. | estebank wrote: | let else and let chains aren't new traits, they are | syntactical features that make things that people would | expect to work, Just Work(tm). People keep bringing up | the complexity of Rust (a valid argument to be made | there) but then point at some feature that is _removing | an arbitrary limitation_ from the language. And even for | cases where a new feature is being added, I can point at | the case of ? for error handling that _was_ a _new_ | feature, that "complicated" the language, but that _very | clearly_ improved the ergonomics of the language for | reading and writing. Should ? have been left in the | cutting floor because it didn 't look like anything else | and was a "redundant" feature? | | Let me put it another way: what Rust feature would you | _remove_ to "simplify" the language? | UmbertoNoEco wrote: | As I pointed here originally, you need to be very careful | about what you ADD to a language, because once the cat is | out of the bag there is no going back, people are going | to use that stuff. That's why I dont begrudge the | attitude of the golang maintainers to be very slow in | introducing stuff, because it is basically an | irreversible step. | | I suppose every thing in Rust has a raison d'etre but you | pay with complexity that versatility. I think there is | space now for a modern, memory-safe, SIMPLE, systems | programming language. C has the backwards compatibility | problem (although I am still bullish on its future) and a | language like Zig never got any traction. Hopefully the | future will bring new, interesting stuff. | aaron_m04 wrote: | I have noticed this tendency as well. | | To counteract it, I write exit-early code like this: | let foo_result = foo(); if let Err(e) = foo_result { | return Bar::Fail(e); } let foo_result = | foo_result.unwrap(); ... | gardaani wrote: | Early exit code would be easier to write if Rust supported | guard let. | veber-alex wrote: | its coming soon, already available on nightly. | let Some(x) = foo() else { return 42 }; | klodolph wrote: | Like this? if let Ok(x) = my_func() { | // ... } | | Or do you mean something else? | ntoskrnl wrote: | I do this too, with a different spin on it: | let foo = match foo() { Ok(foo) => foo, | Err(err) => return Err(err), }; | | I was typing it out so often I made editor aliases `lmo` | and `lmr` for Option and Result | veber-alex wrote: | let me introduce you to the famous '?' operator. | | The code above can be written as: let foo | = foo()?; | ntoskrnl wrote: | LOL you're right! I just pasted the template here, but my | defaults are mostly equivalent to plain old `?`. I don't | use the match if `?` would work. | metaltyphoon wrote: | Isn't that a good general practice todo? Exit early | mathstuf wrote: | Any reason why this wasn't preferred? let | foo_result = foo() .map_err(Bar::Fail)?; | veber-alex wrote: | Bar::Fail is not wrapped in a Result type, so you can't | use '?' with it (on stable at least). | | You can write it like this: let | foo_result = match foo() { Ok(v) => v, | Err(e) => return Bar::Fail(e) }; | loeg wrote: | The result type is the return from Foo -- Bar::Fail does | not need to wrap Result. Foo is Result<T, E> and | map_err() would convert it to Result<T, Bar::Fail>. I | think GP's `map_err()?` is the most straightforward way | of writing this idea (and it's generally speaking how I | would suggest writing Rust code). | veber-alex wrote: | GP's code will return Result<_, Bar>, the original code | we are trying to fix just returns Bar. | loeg wrote: | If you are writing code to handle Results, it's going to | be a lot less painful to just return Result. | kzrdude wrote: | I think it's because of the expression focus. Isn't it easier | to make the code flow like a waterfall when it's imperative, | but is harder to reason about values and state. | dingoegret12 wrote: | I love Rust and use it everyday but the syntax bloat is | something I will never get over. I don't believe there's | nothing that could be done about it. There are all sorts of | creative grammar paths one could take in designing a language. | An infinite amount, in fact. I would really like to see | transpiler that could introduce term rewriting techniques that | can make some of that syntax go away. | TheSoftwareGuy wrote: | Rust has an extremely powerful macro system, have you tried | that? | alpaca128 wrote: | Rust macros are one of the more annoying features to me. | They're great at first glance but whenever I want to build | more fancy ones I constantly bump into limitations. For | example they seem to be parsed without any lookahead, | making it difficult to push beyond the typical function | call syntax without getting compiler errors due to | ambiguity. | inferiorhuman wrote: | Procedural macros have a peek function from the syn | crate. macro_rules macros can stuff this into the pattern | matching. | | e.g. | | https://turreta.com/2019/12/24/pattern-matching- | declarative-... | zozbot234 wrote: | "Creative" grammar introduces parsing difficulties, which | makes IDE tooling harder to build and less effective overall. | My overall guess is that Rust made the right choices here, | though one can endlessly bikeshed about specifics. | klodolph wrote: | Creative grammar can introduce parsing difficulties, but it | doesn't have to. | | I've made a couple small languages, and it's easy to end up | lost in a sea of design decisions. But there are a lot of | languages that have come before yours, and you can look to | them for guidance. Do you want something like automatic | semicolon insertion? Well, you can compare how JavaScript, | Python[1], Haskell, and Go handle it. You can even dig up | messages on mailing lists where developers talk about how | the feature has unexpected drawbacks or nice advantages, or | see blog posts about how it's resulted in unexpected | behavior from a user standpoint. | | You can also take a look at some examples of languages | which are easy or hard to parse, even though they have | similar levels of expressivity. C++ is hard to parse... | why? | | You'd also have as your guiding star some goal like, "I | want to create an LL(1) recursive descent parser for this | language." | | There's still a ton of room for creativity within | constraints like these. | | [1]: Python doesn't have automatic semicolon insertion, but | it does have a semicolon statement separator, and it does | not require you to use a semicolon at the end of | statements. | pizza234 wrote: | > you can look to them for guidance. Do you want | something like automatic semicolon insertion? Well, you | can compare how JavaScript, Python[1], Haskell, and Go | handle it | | You can't look at JavaScript/Python/Go (I don't know | about Haskell), because Rust is a mostly-expression | language (therefore, semicolons have meaning), while | JavaScript/Python/Go aren't. | | The conventional example is conditional assignment to | variable, which in Rust can be performed via if/else, | which in JS/Python/Go can't (and require alternative | syntax). | klodolph wrote: | > You can't look at JavaScript/Python/Go (I don't know | about Haskell), because Rust is a mostly-expression | language (therefore, semicolons have meaning), while | JavaScript/Python/Go aren't. | | I have a hard time accepting this, because I have done | exactly this, in practice, with languages that I've | designed. Are you claiming that it's impossible, | infeasible, or somehow impractical to learn lessons from | -- uhh -- imperative languages where most (but not all) | programmers tend to write a balance of statements and | expressions that leans more towards statements, and apply | those lessons to imperative languages where most (but not | all) programmers tend to write with a balance that tips | more in the other direction? | | Or are you saying something else? | | The fact that automatic semicolon insertion has appeared | in languages which are just so incredibly different to | each other suggests, to me, that there may be something | you can learn from these design choices that you can | apply as a language designer, even when you are designing | languages which are not similar to the ones listed. | | This matches my experience designing languages. | | To be clear, I'm not making any statement about | semicolons in Rust. If you are arguing some point about | semicolon insertion in Rust, then it's just not germane. | KptMarchewa wrote: | Tooling should not depend on code text, but on language's | AST. | nightski wrote: | I'm not an expert as I do not work on these tools but I | don't think IDEs can rely solely on ASTs because not all | code is in a compilable state. Lots of times things have | to be inferred from invalid code. Jetbrains tools for | example do a great job at this. | tripa wrote: | Comments tending to skip on being a part of the AST make | that harder. | darthrupert wrote: | Nim, which technically accomplishes all (I assume) of the | Rusty things that require syntax, manages to do it with quite | a lot nicer syntax. | ben-schaaf wrote: | Nim accomplishes memory safety using a garbage collector. | That's pretty dissimilar to rust and more comparable to go | or D. | cb321 wrote: | While tracing garbage collection is indeed _one possible_ | automatic memory management strategy in Nim, the new | --mm:arc may be what darthrupert meant. See | https://uploads.peterme.net/nimsafe.html | | Nim is choice. :-) {EDIT: As DeathArrow also indicated! } | avgcorrection wrote: | Reference counting is a form of garbage collection. | cb321 wrote: | Terminology in the field can indeed be confusing. In my | experience, people do not seem to call reference counted | C++ smart pointers "garbage collection" (but sure, | one/you might, personally). | | "Automatic vs manual" memory management is what a casual | PL user probably cares about. So, "AMM" with later | clarification as to automation options/properties is, I | think, the best way to express the relevant ideas. This | is why I said "tracing GC" and also why Nim has recently | renamed its _--gc:xxx_ CLI flags to be _--mm:xxx_. | | Whether a tracing collector is even a separate thread or | directly inline in the allocation code pathway is another | important distinction. To muddy the waters further, many | programmers often mean the GC _thread(s)_ when they say | "the GC". | | What runtimes are available is also not always a "fixed | language property". E.g., C can have a tracing GC via | https://en.wikipedia.org/wiki/Boehm_garbage_collector and | you can get that simply by changing your link line (after | installing a lib, if needed). | avgcorrection wrote: | I see now that the GP wrote "a garbage collector" (not | the article). Oops! "A reference counting method" doesn't | roll off the tongue. So it appears that your nitpicking | was indeed appropriate. | DeathArrow wrote: | Nim allows you to chose what memory management method you | want to use in a particular piece of software. It can be | one of various garbage collectors, reference counting or | even no memory management. It allows you to use whatever | suits your needs. | avgcorrection wrote: | > > Nim accomplishes memory safety using a garbage | collector. | | No memory management in Nim equals no memory safety | guarantees. Or no? Well in that case the statement above | is true. | cb321 wrote: | You can get management and safety with one of Nim's | modes, as per the peterme link in my sibling, if you | would like to learn more. | avgcorrection wrote: | I don't understand why you all are posting tedious | details and well actuallys when the original assertion | was (way back): | | > Nim, which technically accomplishes all (I assume) of | the Rusty things that require syntax, manages to do it | with quite a lot nicer syntax. | | Nim does not have something which gives _both_ memory | safety _and_ no ((tracing garbage collector) and /or | (reference counting)) _at the same time_. End of story. | | The fact that Nim has an off-switch for its automatic | memory management is totally uninteresting. It hardly | takes any language design chops to design a safety-off | button compared to the hoops that Rust has to jump | through in order to keep its lifetimes in check. | cb321 wrote: | >Nim does not have something which gives | | You are simply incorrect, appear unwilling to research | why/appear absolutist rather than curious, and have made | clear that what I think is "clarification" or "detail | expansion" you deem "tedious" or "nitpicking" while | simultaneously/sarcastically implicitly demanding more | details. That leaves little more for me to say. | avgcorrection wrote: | You have managed to point out that tracing garbage | collection and reference counting are indeed two ways to | manage memory automatically. Three cheers for your | illuminating _clarification_. | djur wrote: | I'm curious what that assumption is based on. Rust and Nim | are pretty different, and both of them have features that | the other doesn't even try to have. | j-james wrote: | This is an interesting comparison of memory semantics I | stumbled upon: https://paste.sr.ht/blob/731278535144f00fb | 0ecfc41d6ee4851323... | | Nim's modern memory management (ARC/ORC) is fairly | similar to Rust. ARC functions by reference-counting at | compile time and automatically injecting destructors: | which is broadly comparable to Rust's ownership + borrow | checker. | | (A big difference is that Nim's types are Copy by | default: this leads to simpler code at the expense of | performance. You have control over this, keeping memory | safety, with `var`, `sink`, and others, as highlighted in | the above link.) | | https://nim-lang.org/blog/2020/10/15/introduction-to-arc- | orc... | | For reference cycles (the big limitation of reference | counting), there's ORC: ARC + a lightweight tracing | garbage collector. | | As I understand it Rust also cannot handle reference | cycles without manually implementing something similar. | | https://nim-lang.org/blog/2020/12/08/introducing-orc.html | | https://doc.rust-lang.org/book/ch15-06-reference- | cycles.html | sophacles wrote: | It's a pain to write all that boilerplate, I agree. I don't | think it's bloat though - I've been doing rust for a few | years now, and when I revisit old mostly forgoten code, I | love that boilerplate. I rarely have to do any puzzling about | how to infer what from the current file, it's just all right | there for me. | | I feel this way about all the verbosity in rust - some of it | could likely be inferred, but but having it all written down | right where it is relevant is great for readability. | carlmr wrote: | That's true, I found this writing F# with an IDE vs reading | F# in a PR without IDE it really becomes easier to read if | you at least have the types on the function boundary. | | F# can infer almost everything. It's easier to read when | you do document some of the types though. | worik wrote: | Having done a bit of C lately (lots in the past) and quite | a bit of Rust, Rust is not verbose! | | The functional syntax the author of this (good) article | complains about is what this (long experience in procedural | C like languages) old programmer has come to love. | dhosek wrote: | Familiarity also alleviates the issue. I can remember when I | first encountered TeX in the 80s and Perl in the 90s and | thought the code looked like line noise and now I no longer see | that (even in Larry Wall-style use-all-the-abbreviations Perl). | sidlls wrote: | It alleviates the issue the way the frog doesn't notice in | the "boiling frog" fable. That is, not in a good way. The | cognitive load to parse and understand it is still there; | you're just not as aware of it distracting from other | matters. Some (me) would say it distracts from more important | things, like how units of code compose and what the purpose | of a program is. | cardanome wrote: | The problem is that familiarity needs to be maintained or you | can lose it. As someone that doesn't get to use Rust at my | day job that can be hard to keep fresh. | | I only occasionally dabble in Rust in my free time and coming | back to a project of mine after months of not having used any | Rust, yeah lets just say that line noise made me prematurely | murder some of my pet-projects. | | Sure it gets probably better with time but still it is a cost | that one pays. | riskable wrote: | > ...thought the code looked like line noise and now I no | longer see that | | "I don't even see the code anymore. I just see blonde, | brunette, ..." | | I myself have _just_ started to get like that with my | understanding of Rust: | | "I don't even see the `impl<P: 'static, const PS: usize> | IndexMut<usize> for SomeThing<P, PS>` anymore. I just see a | mutable iterator." | jillesvangurp wrote: | Something like Kotlin but with a borrow checker might be the | ultimate in developer ergonomics for me. I sat down at some | point to wrap my head around Rust and ended up abandoning that | project due to a lack of time. And because it was hard. The | syntax is a hurdle. Still, I would like to pick that up at some | point but things don't look good in terms of me finding the | time. | | However, Rust's borrow checker is a very neat idea and one that | is worthy of copying for new languages; or even some existing | ones. Are there any other languages that have this at this | point? | | I think the issue with Rust is simply that it emerged out of | the C/C++ world and they started by staying close to its syntax | and concepts (pointers and references) and it kind of went down | hill from there. Adding macros to the mix allowed developers to | fix a lot of issues; but at the price of having code that is | not very obvious about its semantics to a reader. It works and | it's probably pretty in the eyes of some. But too me it looks | like Perl and C had a baby. Depending on your background, that | might be the best thing ever of course. | zozbot234 wrote: | Rust and Kotlin have very similar syntax. The main | differences are semantics-related, such as Kotlin relying on | GC. | cogman10 wrote: | The borrow checker doesn't really work without lifetime | annotations. When I see complaints about rust, that's seems | to be the thing most are talking about. The issue is the | notion of an object lifetime is a hard thing to express with | familiar type systems. It's an unfamiliar concept. | cies wrote: | Maybe we've reached the limits of the complexity we can handle | in a simple text-based language and should develop future | languages with IDEs in mind. IDEs can hide some of the | complexity for us, and give access to it only when you are | digging into the details. | robonerd wrote: | The problem with this premise is that by raising the bar for | any IDE that wants to support that language, you risk the | creation of an IDE monoculture. | xxpor wrote: | Is that as true any more with the language server model? | | I'm not familiar enough with it to know how much is truely | in the protocol vs what the editor still has to do | themselves. | robonerd wrote: | LSPs are great, I think they've proven fairly easy to | integrate into many text editors. But consider something | like the Scratch programming language. How many editors | support Scratch? Once you stray from code-as-text, adding | support to old editors often becomes infeasible and the | effort needed to create new editors is a significant | barrier to entry. | flohofwoe wrote: | This just plasters over the underlying problem, which in case | of Rust is IMO that features that should go into the language | as syntax sugar instead are implemented as generic types in | the standard library (exact same problem of why modern C++ | source code looks so messy). This is of course my subjective | opinion, but I find Zig's syntax sugar for optional values | and error handling a lot nicer than Rust's implementation of | the same concepts. The difference is (mostly): language | feature versus stdlib feature. | marcosdumay wrote: | Rust developers are doing an awesome job of identifying | those things and changing the language to meet it. Today's | Rust is much cleaner than it was 5 years ago (or 8 if you | count nightly). | | But yes, there is still a lot of it. | | Anyway, most of the noise comes from the fact that Rust is | a low level language that cares about things like memory | management. It's amazing how one is constantly reminded of | this by the compiler, what is annoying, but the reason it | doesn't happen on the alternatives is because they never | let you forget about that fact. | vlovich123 wrote: | I'm not familiar with zig. Can you give some examples to | illustrate your point? | flohofwoe wrote: | An optional is just a '?' before the type: | | For instance a function which returns an optional pointer | to a 'Bla': fn make_bla() ?*Bla { | // this would either return a valid *Bla, or null | } | | A null pointer can't be used accidentally, it must be | unwrapped first, and in Zig this is implemented as | language syntax, for instance you can unwrap with an if: | if (make_bla()) |bla| { // bla is now the | unwrapped valid pointer } else { // | make_bla() returned null } | | ...or with an orelse: const bla = | make_bla() orelse { return error.InvalidBla }; | | ...or if you know for sure that bla should be valid, and | otherwise want a panic: const bla = | make_bla().?; | | ...error handling with error unions has similar syntax | sugar. | | It's probably not perfect, but I feel that for real-world | code, working with optionals and errors in Zig leads to | more readable code on average than Rust, while providing | the same set of features. | veber-alex wrote: | I don't see how that is all that different from Rust. | | The main difference I see is that in Rust it will also | work with your own custom types, not just optional. | fn make_bla() -> Option<Bla> { // this either | returns a valid Bla, or None } if let | Some(bla) = make_bla() { // bla is now the | unwrapped valid type } else { // make_bla() | returned None } | | ..or with the '?' operator (early return) | let bla = make_bla().ok_or(InvalidBla)?; | | ..or with let_else (nightly only but should be stable | Soon(tm)) let Some(bla) = make_bla() else | { return Err(InvalidBla) } | | ..or panic on None let bla = | make_bla().unwrap(); | shadowofneptune wrote: | The same information can be communicated in different ways, | trading one form of noise for another. I have a personal | preference for Pascal-like or PL/I syntax. Instead of int *char | x or int&& x, there's x: _byte_ _ptr_ _ptr_. It 's more to type | and read, sure, but sometimes having an english-like keyword | really helps clarify what's going on. | robonerd wrote: | > _It 's more to type and read_ | | I wouldn't even say that. Using words (or multi-letter | symbols generally) may be more to type, but virtually | everybody uses editors with completion features and those | completion features tend to work better with words than | symbols. Furthermore, despite there being more characters, I | don't think it's actually more to read. People who are fluent | in reading languages written with alphabet systems don't read | letter-by-letter, but instead read word-by-word, using | effortless word recognition. | jnwatson wrote: | Typing words is faster than symbols for most folks even | without an IDE. Typing `&{% takes way longer than "static | long foo". | zozbot234 wrote: | > People who are fluent in reading languages written with | alphabet systems don't read letter-by-letter, but instead | read word-by-word, using effortless word recognition. | | It all adds up. Languages like COBOL, PASCAL or ADA | (originally designed for terminals with very limited | character sets, sometimes even lacking lowercase text - | thus requiring case-insensitive syntax) make it a lot | harder to survey larger code blocks. | robonerd wrote: | > _It all adds up._ | | If that's true, I would expect logographic writing | systems to cause less reader fatigue than alphabetic | writing system. But as far as I'm aware that isn't the | case, and the two are roughly equivalent. | nu11ptr wrote: | I agree, and my ideas for alternative syntax were effectively | this. They were, in my opinion, a slight improvement, but | still result in lots of syntax. My point is that while I | might want a more "python-like" or "ML-like" syntax we often | forget that it simply isn't possible in the same way those | languages use it, and by the time we add all the extra things | we need, it doesn't look that much less "noisy". | Banana699 wrote: | The english words preference is a cliche that has been argued | back and forth, to heaven and hell, since Cobol. I'm | sympathetic to your opinion in some cases, but ultimately it | fails in my view. Terse notations requires an investment in | the beginning but then pay off massively with increased | bandwidth, you can hold more of the code in your head. You | don't see math being done by (x.plus(y)).pow(3), you see it | done by (x+y)^3, it gets even worse when expressions increase | in size. | | Ideally, the language should have enough syntax-bending | facilities so that you can still simulate what you want, this | is mostly just operator overloading and not treating custom | types like second class citizens. For example, your example | of byte ptr ptr can be easily done in C++ by a bytePtrPtr | struct, or even better, a Ptr<Ptr<Byte>> instantiated class | from the template Ptr<T> for any T. Overloading the | dereference and conversion operators will completely hide any | trace of the fact it's not a built in type, and compiler | optimization and inlinning will (hopefully, fingers crossed) | ensure that no extra overhead is being introduced by the | abstraction. | | As for the 'byte ptr ptr' syntax specifically, in F# generic | instantiation can be done by whitespace concatenation of type | names in reversed C++/Java/C# order, so the above C++ type | would (if translated to F# somehow) literally be written out | as you want it to be, so even what seems like it would | require language support (whitespace between related | identifiers, generally a tricky thing in PL design) can | actually be accomplished with clever and free minded syntax. | shadowofneptune wrote: | That is a good point about typedefs, and I would hate to be | using 'ADD 1, a, b TO x ROUNDED' instead of 1 + a + b + | round(x). I'll also have to check out F#. | singularity2001 wrote: | I think making things syntactically explicit which are core | concepts is stupid: | | ```pub fn horror()->Result{Ok(Result(mut &self))}``` | | A function returns a Result. This concept in Rust is so | ubiquitous that it should be a first class citizen. It should, | under all circumstances, be syntactically implicit: | | ```pub fn better->self``` | | No matter what it takes to make the compiler smarter. | dllthomas wrote: | Others have addressed the problem with "implicit", but I | might be on board with "lightweight"; maybe in a type context | `T?` can mean `Result<T>` for whatever Result is in scope? | That way you can still define functions with various distinct | error types the same as today, but the common (idk just how | common, not claiming a majority) case of using the same error | across a module or package with a Result type alias will get | cleaner. | dragonwriter wrote: | > A function returns a Result. | | That is not, in fact, a core concept in Rust. Plenty of | functions have no reason to return Result. (And some that do | also have a reason for the inner class to be a result.) | | > This concept in Rust is so ubiquitous that it should be a | first class citizen. It should, under all circumstances, be | syntactically implicit: | | "Implicit" is an opposed concept to "first-class citizen". | Result is first-class in Rust, and would not be if function | returns were implicitly Result. | jherico wrote: | dragonwriter wrote: | > I remain convinced that the whole Result concept was | just created by people butt-hurt over the concept of | exceptions | | I wouldn't use the emotionally-loaded dismissive | language, but, yes, Result is a solution to the same | problem as exceptions that deals with several problems of | exceptions, including: | | (1) Unchecked exceptions obscure what is going on, and | frustrate analysis because things remote from the code | may bypass it in the call-stack without any evidence | visible in signatures. | | (2) Checked exceptions are clear, but create a separate | syntax for expressing type-like constraints, also | limiting what you can do around them _because_ they aren | 't the same thing as types. | | Results are basically cleaner checked exceptions. | jherico wrote: | I'll certainly grant that unchecked exceptions are | problematic for static analysis, but in regards to your | second point, I don't feel like Rust has actually avoided | creating "a separate syntax". It's created a different, | more complex syntax which must be adopted inline in your | actual normal code path, obfuscating what your code is | actually expected to do under non-error conditions. | | IMO, one of the most valuable pieces of exception | handling is a distinct separation between your error | logic and your non-error logic, which makes methods | easier to comprehend. I also feel like the existence of | the ? syntax is a dead giveaway in this regard because | it's a fig-leaf trying to cover up the most egregious | parts of the code where you'd otherwise have to be write | the frequent "if error then early return error" | statements which plague Golang. | singularity2001 wrote: | > Result is not a core concept in Rust. | | If you don't see std::result::Result as a core concept in | Rust, which might be fair, one can still argue that it | _should_ be a core concept, given its ubiquitous usage. | dragonwriter wrote: | You misquoted, I never said Result is not a core concept. | | What I said is that "A function returns Result" in the | universal sense (that is, everything that is a function | returns Result) is not a core concept in Rust. | | Some functions return Result<T,E> for some <T,E>. Some | functions return Option<T> for some T. Some functions | have no reason to use that kind of generic wrapper type | (a pure function that handles any value in its range and | returns a valid value in a simple type for each doesn't | need either; Option/Result are typically needed with | otherwise non-total functions or functions that perform | side effects that can fail.) | pcwalton wrote: | This would break the principle that you always know how to | invoke a function by looking at its signature. Option of T | and Result of T are not the same type as T. You would have to | look at the body of the function, or rustdoc, to know how to | invoke it, which would be very annoying. | | Besides, what is the error type for Result? You haven't | declared it. | runevault wrote: | Your summary is the thing I struggle with as well. How do you | deal with the issues of density without either making it more | verbose by a wide margin (which also hampers readability) or | hiding information in a way that makes the code less obvious | which is, IMO, worse. | | Software is becoming more and more complex and unless there are | entirely different design patterns we have failed to find, | managing and understanding that during both the writing and the | maintenance of software is the fundamental problem of our time. | Someone else in these comments mentioned leaning more heavily | into IDE tooling and I do wonder if we are coming to a point | where that makes sense. | ModernMech wrote: | > unless there are entirely different design patterns we have | failed | | It's not that we've failed to find different design patterns, | it's that we found these patterns in the 70s and haven't done | much with them since. Since C there has been a pretty | constant march toward more imperative programming, but | imperative programming I feel has reached its peak for the | reasons you describe. | | We're only _just_ starting to explore the functional | programming space and incorporate those learnings into our | work. But what about logic programming, dataflow programming, | reactive programming, and other paradigms that have been | discovered but not really fully explored to the extent | imperative programming has been? I think there's a lot of | room for improvement just by revisiting what we've already | known for 50 years. | api wrote: | IMHO it's at least somewhat better than "modern" C++ where you | end up having to wrap virtually every single thing in some kind | of template class, and that's without the benefit of much | stronger memory and thread safety. | | Overall I think Rust is a hands-down win over C and C++. People | who want it to be like Go are probably not doing systems-level | programming, which is what Rust is for, and I have severe | doubts about whether a rich systems-level language could be | made much simpler than Rust and still deliver what Rust | delivers. If you want full control, manual memory management | with safety, other safety guarantees, a rich type system, high | performance, and the ability to target small embedded use | cases, there is a certain floor of essential complexity that is | just there and can't really be worked around. Your type system | is going to be chonky because that's the only way to get the | compiler to do a bunch of stuff at compile time that would | otherwise have to be done at runtime with a fat runtime VM like | Go, Java, C#.NET, etc. have. | | Go requires a fat runtime and has a lot of limitations that | really hurt when writing certain kinds of things like high | performance codecs, etc. It's outstanding for CRUD, web apps, | and normal apps, and I really wish it had a great GUI story | since Go would be a fantastic language to write normal level | desktop and mobile UI apps. | Night_Thastus wrote: | For what purpose would you need to wrap everything in a | template class? In my work, I've only touched templates a | couple of times in years. They're useful, but I don't see how | it's always needed. | ben-schaaf wrote: | std::unique_ptr and std::shared_ptr are templated wrapper | classes. | Night_Thastus wrote: | Oh. I misunderstood. I was thinking of user-made | templates, not the built-in ones from the standard | library. I don't see the issue though. Something like | vector feels intuitive. I have a vector<int> or a | vector<myType> etc. A pointer to an int, a | unique_ptr<int>. It's convenient and fairly flexible. I | don't really see the downside, or how it could be done | better given static typing. | queuebert wrote: | Completely agree. I think of the extra syntax as us helping the | compiler check our code. I have to write a few more characters | here and there, but I spend _way_ less time debugging. | | Although I may have PTSD from Rust, because lately I find | myself preferring Qbasic in my spare time. -\\_(tsu)_/- | agumonkey wrote: | Probably a very general response to overload of any kind.. | you start to reevaluate the opposite side of the spectrum. | smegsicle wrote: | the dialectical method | agumonkey wrote: | I'd have used the 'banging on both guard rails but yours | sounds better. | singularity2001 wrote: | >>> I'm not convinced much could have been done about it. | | Are you sure? What stops Swift with its beautiful syntax and | safe optionals from becoming a systems language? | tayistay wrote: | Perhaps not that that much. Swift's arrays are refcounted. | And you can't store an array on the stack. Classes are | refcounted too, but you could avoid them. It also has a bit | of a runtime, and you don't know when it will take locks or | allocate (though there is work to tag functions so they can't | do either). | pjmlp wrote: | System languages on the Algol/Wirth branch prove otherwise. | | They can be ergonomic high level, while providing the language | features to go low level when needed. | titzer wrote: | Agree, and even C got really far without traits. Traits are a | lot of rope for building confusing abstractions, IMHO. | ducktective wrote: | About the installation method ('hi! download this random shell | script and execute it'), I agree this is really dangerous but | mere installing stuff is a hairy thing on linux distros. I mean | what is the practical alternative? Distro package manager | versions are almost always way behind. | | NixOS/guix are gonna solve this issue once and for all (famous | last words) | mjw1007 wrote: | Here are some things that they could do better: | | - the domain in the curlbashware URL could be less shady than | sh.rustup.rs | | - the "rustup is an official Rust project" claim on | https://rustup.rs/ could be a link to a page somewhere on rust- | lang.org that confirms that rustup.rs is the site to use | pmoriarty wrote: | _" the domain in the curlbashware URL could be less shady | than sh.rustup.rs"_ | | Relying on a familiar looking domain doesn't get you much | security, especially with internationalized domain names | where what a domain name appears like in one language could | actually be very different in another. | marcosdumay wrote: | I imagine people type that string on their terminals. | Pasting things there is full of issues, and it's not long. | __ryan__ wrote: | - the domain in the curlbashware URL could be less shady than | sh.rustup.rs | | The domain is only as shady as it is unfamiliar. It's not | shady to me since I recognize it as the canonical domain of | the recommended installer for Rust, "rustup". | - the "rustup is an official Rust project" claim on | https://rustup.rs/ could be a link to a page somewhere on | rust-lang.org that confirms that rustup.rs is the site to use | | It links to rust-lang.org, whose installation page then | describes rustup as the recommended way to install [0]. I | suppose it could link directly to the page, but what really | does that gain? | | 0: https://www.rust-lang.org/tools/install#rustup | amalcon wrote: | It's shady because it's under the TLD for Serbia, while | having no obvious connection to Serbia. I have nothing | against Serbia, but the Rust project doesn't seem to have | any special relationship to that country. | | In HN and similar places, it is pretty normal to see a cc- | tld used purely because the abbreviation fits. Not everyone | is used to that, though. If it were e.g. | https://rustup.dev/, that would mitigate this concern. | __ryan__ wrote: | By that logic https://github.io is _shady_. | | Also, a bad actor could just as well register | https://rustup.dev. Rather than judging a URL in a vacuum | based on the TLD, you should instead cross reference the | official docs and confirm that the URL is correct. | amalcon wrote: | Is it not? If GitHub were asking me to download and run | code from a github.io subdomain without checking a | signature, or something of similar risk level, I'd be | concerned. I'd also be _correct_ to be concerned, since | anyone can put anything in a github.io subdomain -- I 'd | need to make sure that github actually owns that repo. | Strictly speaking that's orthogonal, and github does | actually own the github.io domain. The domain still seems | suboptimal to me, but I don't make those decisions. | | And yes, a bad actor could just as easily register | rustup.dev. Nobody ever claimed that checking the TLD is | sufficient to make a site trustworthy; only that it | appears a bit shady. Unless you're already familiar with | Rust (or at least with a particular aspect of startup | culture), there's no obvious reason to choose .rs. On the | other hand, domains in somepopularsite.unrelatedtld have | been a phishing staple for decades -- making the shady | vibe at least a little bit reasonable. | __ryan__ wrote: | I meant that the logic implies that https://github.io is | shady _because_ it uses the ccTLD of British Indian Ocean | Territory despite being unrelated. | | Of course you should cross reference the authenticity of | any URL you are about to execute as a shell script. No | one is saying not to. | | But your point seems to agree with mine: it's only as | shady as it is unfamiliar. The answer shouldn't be to | come up with a URL that lowers your guard. Instead, users | should get familiar. | maccard wrote: | But it's not really dangerous, no more so than downloading an | arbitrary binary and executing it at least. The script is | delivered over https, so you're not going to be MITM'ed, and | you're trusting rustup to provide you the valid install script. | If you _are_ MITM'ed, it doesn't really matter what your | delivery method is unless you do a verification from another | device/network, and if you don't trust rustup then why are you | downloading and executing their installer? | ducktective wrote: | If they `shellcheck` their bash script, then sure. Aside from | unquoted $vars, usually random shell scripts have a habit of | polluting home and creating arbitrary dirs under god-knows- | where and not respecting XDG. | | They are almost always irreversible too. Like you can't undo | the steps the shell scripts have done. | __ryan__ wrote: | _Any_ software you choose to run could not respect your | desires and leave a mess. This is not a random shell | script. It 's the officially recommended way to install | Rust [0], vetted and maintained by the community. You're | free to audit the script before running it, or even check | out the source [1]. If this doesn't satisfy you, check out | the other installation methods [2]. | | Edit: I realize you're not speaking specifically about | rustup, but what I said can and should apply to anything | you choose to install this way. | | 0: https://www.rust-lang.org/tools/install#rustup | | 1: https://github.com/rust-lang/rustup | | 2: https://forge.rust-lang.org/infra/other-installation- | methods... | marcosdumay wrote: | > Any software you choose to run could not respect your | desires and leave a mess. | | On most languages, you must decide to do it to create a | mess. Bash is almost alone on the place where you can do | it by accident. | maccard wrote: | A syntax error in any scripting language will have the | exact same problem. | marcosdumay wrote: | Problems like removing a large directory instead of a | file, creating your files on random places instead of the | directory you pass on, or creating more files than you | intended? | | The one mess you see from other languages is creating | files on the wrong place (or all over the place). But not | those above. | maccard wrote: | > Problems like removing a large directory instead of a | file | | rm doens't do that unless you explicitly tell it to. | | > Problems like removing a large directory instead of a | file, creating your files on random places instead of the | directory you pass on, or creating more files than you | intended? | | But yes, all of these can and do exist in other | languages. Using python as an example, if you read an | environment variable without checking it's set (as in the | infamous steam bug) [0], you'll end up with pretty much | the exact same behaviour. You can misindent your loop in | python and not create/remove files that you intend to, or | your script can have a syntax error halfway through and | the interpreter will happily proceed until it halts, and | leave you in a half baked state just like bash does. | | [0] https://github.com/valvesoftware/steam-for- | linux/issues/3671 | __ryan__ wrote: | Any tool can be dangerous in inexperienced or careless | hands. The issues you described could just as likely be | caused by logic errors or typos in any other language. | | You're talking as if all bash scripts are hacked together | carelessly and work by accident. You can actually _learn_ | bash. Thankfully the script we're discussing is written | with care and vetted by the community. | Problems like removing a large directory instead of a | file | | The _rm_ command doesn't even remove directories by | default, you have to specify a flag. Not knowing a tool | is not a good reason to bash it. | marcosdumay wrote: | Isn't Rust one of those languages based on the idea that | tools matter and that should either be correct or | obviously wrong? | | (And no, those problems do usually not appear due to | logic errors or typos in other languages. It's very, very | rare.) | | I'm well aware that the Rust installation script is well | vetted and stable enough to be reliable. Bootstraping a | development environment is also a real problem, with no | good answers. It's understandable that they want to | bootstrap from Bash. But as understandable as it is, it | still carries the Bash issues with it. | | Of course, the optimum solution would be to do it from | your system's tools. That is something that will probably | happen naturally given enough time. | maccard wrote: | > Isn't Rust one of those languages based on the idea | that tools matter and that should either be correct or | obviously wrong? | | It doesn't really matter, if you combine `/home/myuser` | and some unsantized input variable, and then call | `remove_dir_all` [0], it doesn't matter how safe the | language is, you're going to delete your entire home | directory with absolutely no warning, whether it's in | bash, go, python, rust or haskell. Yes bash makes this | very easy to do, but so does pretty much every language | in existence. | | > (And no, those problems do usually not appear due to | logic errors or typos in other languages. It's very, very | rare.) | | They absolutely do. Here's an explosive script in golang | (deliberately doesn't compile just in case) - running | this in func main() will ruin your day most likely. | dirToRemove := "~/" + os.Getenv("BAD_ENV_VAR") | os.RemoveAll(dirToRemove | | I can write one of these in bash, python, go, you name | it. | | [0] https://doc.rust- | lang.org/std/fs/fn.remove_dir_all.html | maccard wrote: | The same can be said for any badly written python script, | or golang binary too. | IshKebab wrote: | > this is really dangerous | | People repeat this a lot but really it just _seems_ dangerous. | Can you give an example of a scenario where offering a download | via `curl | bash` is more dangerous than "download this | installer with the hash 01234 and then execute it"? | ben0x539 wrote: | The site could detect that it's invoked as part of a `curl | | bash` and sometimes serve a different script than you would | get if you manually downloaded the script or the installer | for manual inspection/auditing, making it harder to detect | shenanigans. I think someone wrote this up as a PoC/blog post | at some point. | otterley wrote: | > NixOS/guix are gonna solve this issue once and for all | (famous last words) | | Should we take bets on whether this happens first, or whether | nuclear fusion becomes mainstream first? | NoGravitas wrote: | > This is a superficial complaint, but I found Rust syntax to be | dense, heavy, and difficult to read. | | I'm not sure this _is_ a superficial complaint. People say the | hard thing about learning Rust is the new concepts, but I haven | 't found that to be true at all. The concepts are easy, but the | combinatorial explosion of syntax that supports them is | untenable. | gxt wrote: | I use rust weekly and I find it to have the best DX. I have | done work with Oracle Java 5-8, IBM XL C99, MSVC++11, CPython | 2-3, C# .NET Core 3.1. Stable Rust 2021 is overall the most | readable, least surprising, BUT only with the right tool which | also makes it the most discoverable, with rust-analyzer. My | only gripe is the lack of consensus on strongly typed error | handling (anyhow+thiserror being the most sensible combination | I found after moving away from bare Results, to failure, to | just anyhow). | kkoning wrote: | > but the combinatorial explosion of syntax that supports them | is untenable. | | I wouldn't go quite that far myself, but it's definitely one of | the sharper edges of the language currently--particularly | because some of the features don't work together yet. E.g., | async and traits. | devit wrote: | How would you change the syntax? | | I don't think that Rust has much redundant syntax. | | I guess you could do things like replace &'a Type with Ref<'a, | Type> and *Type with Ptr<Type>, and get rid of some sugar like | "if let" and print!, but I'm not sure that would have much of | an impact. | sidlls wrote: | Back when I wrote C and C++ for a living I'd occasionally meet | someone who thought their ability to employ the spiral rule or | parse a particularly dense template construct meant they were a | genius. I get the same vibe from certain other groups in this | industry, most recently from functional programmers and Rust | afficionados, for example. Nobody gives a damn if you can | narrate a C spiral or a functional-like Rust idiom. | | And this syntax density is one of the reasons I stopped | advocating for the use of Rust in our systems. First, I don't | want to work with languages that attract this kind of person. | Second, I don't want to work with languages that require a | relatively heavy cognitive load on simply reading the lines of | the source code. Units of code (i.e. statements, functions, | structures and modules) are _already_ a cognitive load--and the | more important one. Any extra bit I have to supply to simply | parsing the symbols is a distraction. | | "You get used to it," "with practice it fades to the | background," etc. are responses I've seen in these comments, | and more generally when this issue comes up. They're inaccurate | at best, and often simply another way the above mentioned | "geniuses" manifest that particular personality flaw. No, thank | you. I'll pass. | bbkane wrote: | If not C++ or Rust, what languages do you advocate for now? | sidlls wrote: | Depends on the application, really. And I wouldn't call it | "advocacy" so much as being resigned to accepting a less | odious bad option. In that case, typically Go or Python, | unless we need that last bit of performance and can't get | it with a pre-built library: then I'd argue for C, C++, and | Rust (in that order). | pjmlp wrote: | Not the OP, I rather use managed languages with AOT/JIT | toolchains. | | C++ and Rust I leave for scenarios where choice is imposed | on me due to platform SDKs, or having any kind of automatic | memory management isn't an option. | jgilias wrote: | Rust's memory semantics are definitely a kind of | 'automatic memory management' though. I mean, that's the | whole premise - to have the kind of guarantees about | memory safety that until Rust where only available in | GC'ed languages running on some runtime. | pjmlp wrote: | There is nothing automatic about compiler errors in | lifetimes. | | As for until Rust, Cyclone and ATS did it first. | duped wrote: | > I get the same vibe from certain other groups in this | industry, most recently from functional programmers and Rust | afficionados, for example. | | Another trait in programmers that is worth avoiding is the | false equivalency between C++ template metaprogramming and | generic programming in languages with expressive static | typing. | | It's not clever or inscrutable like templates, quite the | opposite. It's explicit about constraint. Generic Rust makes | it easier to understand complex code and write it correctly. | An immediate red flag for me are programmers who don't "get | it" because they equate that to some kind of SFINAE or | compile time magic they once saw in C++. They're not the same | feature, except superficially. | mmarq wrote: | > I don't want to work with languages that attract this kind | of person | | I haven't used Rust professionally, but I find the community | extremely inclusive and helpful. I joined the Discord server | and asked all sorts of stupid questions and people always | helped me and explained to me what was wrong with my code (or | my assumptions). But, again, I haven't used Rust | professionally and it may be different in that context | | > I don't want to work with languages that require a | relatively heavy cognitive load on simply reading the lines | of the source code | | Strongly agree on this, I haven't tried to introduce it where | I work for the same reason. The cognitive load is massive | compared to a language like C# or JS and the gain is minimal | for the average developer writing microservices for React | frontends. In this context you need a JSON serializer, | iterators and maybe generics, and Rust is not much better | than C# on this front. | rr808 wrote: | > And this syntax density is one of the reasons I stopped | advocating for the use of Rust in our systems. | | Trouble is I've found this type of genius is most languages. | There are always some esoteric functionality that few people | understand that some people will choose because its "the most | appropriate" but largely because its a challenge. Of course | such talented people move on to the next project quickly as | maintaining their crap is not fun. | epage wrote: | > Back when I wrote C and C++ for a living I'd occasionally | meet someone who thought their ability to employ the spiral | rule or parse a particularly dense template construct meant | they were a genius. I get the same vibe from certain other | groups in this industry, most recently from functional | programmers and Rust afficionados, for example. Nobody gives | a damn if you can narrate a C spiral or a functional-like | Rust idiom. | | I think one problem is dealing with "just because you can | doesn't mean you should". It is easy to be nerd-sniped into | optimizing everything in Rust. I've seen complain about an | arg parser using dynamic dispatch when anything the program | actually does will dwarf the time that that takes. I feel we | need a reset; a stdlib-alternative that optimized for those | learning and prototyping at the cost of performance. I | suspect people using that will help break them of the feeling | to optimize the trivial but to instead focus on what | profilers tell them. | voidhorse wrote: | I'm with you. I think people that treat syntax as some | completely unimportant detail are forgetting that reading | code is a more important use case than writing code. | | No matter how much you internalize the syntax of language X, | as the sheer number of syntactic structures in the language | increases, the higher the likelihood you'll misread | something. | robonerd wrote: | > _I get the same vibe from certain other groups in this | industry, most recently from functional programmers and Rust | afficionados_ | | Perl one-liner guys used to exemplify this. But I don't | really agree that functional programmers do, except for | Haskell and people who use lots of the car and cdr | compositions, or those who use too much metaprogramming, | or... okay maybe you're right. But at least the fundamental | premise of functional programming is simple.. | nonameiguess wrote: | I don't use Rust a ton, certainly not enough that the syntax | density fades into the background, but something I'll say for | the ecosystem is rust-analyzer is really good and pretty much | always knows and warns you when you're writing something | incorrectly that won't compile. The worst parts of the syntax | effectively become self-writing, though it does nothing to | help reading. | scythe wrote: | >Second, I don't want to work with languages that require a | relatively heavy cognitive load on simply reading the lines | of the source code. Units of code (i.e. statements, | functions, structures and modules) are already a cognitive | load--and the more important one. Any extra bit I have to | supply to simply parsing the symbols is a distraction. | | The weird thing about these comments to me (as someone who | doesn't use Rust) is that the most difficult syntax in the | original examples represents a _semantic_ detail that most | languages don 't have to deal with: the _lifetime_. The | amount of times I think about the lifetimes of variables I | write in Python is zero. Parsing the symbols and | understanding the code here aren 't separate; that weird | apostrophe thing in angle brackets is a symbol I don't use | referencing a concept I don't use, which fits. If you | replaced the symbols with keywords or something, it would | just be longer, not simpler. | | Also, it's a choice to write your code like he did. You can | define local variables that hold intermediate results and | subexpressions and give them descriptive names, if you want. | You could assign `drop = (|_| ())` for example. | krupan wrote: | One human needs to figure out how to write a line of code once, | and then that line needs to be read and understood by humans | over and over. | | Optimize for readability. Rust doesn't seem to do this. | ModernMech wrote: | It's hard to optimize for readability, performance, and | safety. Rust chose to go with performance and safety. In the | future, maybe we can have a language that gives all three but | not today. | verdagon wrote: | Shameless relevant plug: that's the exact goal of Vale! [0] | | It turns out, when one removes the borrow checker, they get | something that's much more readable, because a lot of | Rust's complexity was added to help support the borrow | checker. | | Ironically, we can then add back in a different, easier | form of borrow checking to get the speed benefits. | | [0] https://vale.dev/ | NoGravitas wrote: | Vale looks exciting. Thanks for the link. | quirino wrote: | It's refreshing to see such a simple, good-looking and | informative website. Also incredibly fast! Please keep it | that way. | vrfvr wrote: | > Rust is also very difficult. It's as complex as C++, | and throws it all at the programmer at once. | | I thin Rust isnt nearly as complex | eternalban wrote: | Same thing that happened with type declarations will need | to happen to semantic intent: inference. | estebank wrote: | Readability seems to mean different things to different | people. You (and many others!) seem to interpret that word as | "there's only relevant information and nothing else in | sight". Personally I interpret it as "I have all the relevant | information available to me in a way I can scan for quickly". | Rust has a higher syntactic load, there are more things | present to the reader, but it also means that everything the | reader _might_ need is always available, and the syntactical | patterns are unique enough that it is "easy" (we can argue | this point forever) to skip things you don't care about. When | I look at type signatures, sometimes I care about the trait | bounds, sometimes I don't. Sometimes I care about the | lifetime relationship between different arguments and the | output, sometimes I don't. Languages that make these | relationships completely implicit make it easy to focus on | _some_ aspects of the code 's behavior, while obscuring | others. | UmbertoNoEco wrote: | Correct, this is more or less like remarking that having to | learn Kanji/Hanzi makes learning Japanese/Mandarin very | difficult is a superficial complaint. | titzer wrote: | I find Rust code hard to read...to the point where I don't feel | motivated to learn it anymore. Line noise is confusing and a | distraction. Random syntactic "innovations" I find are just | friction in picking up a language. | | For example, in the first versions of Virgil I introduced new | keywords for declaring fields: "field", "method" and then | "local". There was a different syntax for switch statements, a | slightly different syntax for array accesses. Then I looked at | the code I was writing and realized that the different keywords | didn't add anything, the array subscripting syntax was just a | bother; in fact, all my "innovations" just took things away and | made it harder to learn. | | For better or for worse, the world is starting to converge on | something that looks like an amalgam of Java, JavaScript, and | Scala. At least IMHO; that's kind of what Virgil has started to | look like, heh :) | perrygeo wrote: | It's not a superficial complaint but it is _relative_ to one 's | experience. Something that's "difficult" for me might be "easy" | for you and vice versa. I find it very much related to | understanding the core concepts. | | I personally find Rust syntax to be quite enjoyable, or at | least it fades into the background quickly - with a few | exceptions. The syntax for lifetime annotations can be | challenging. And not surprisingly explicit lifetime annotations | are a rather unique concept, at least among mainstream | languages. IOW the syntax is difficult because it's an entirely | new mental model (for me), not because `<'a>` is an inherently | bad way to express it. | jmartin2683 wrote: | Rust is awesome. I've been in love since the moment I met it. | tommyage wrote: | I did not read the post, but scanned for the first contra- | argument: A very dense syntax. This is the reason Rust did not | attract me. | | I want to raise the following: Rust is overengineered. If these | highly-intelligent contributors would settle on D, I think | humanity/developer-community would archive more collaborations on | essential pieces of software. | | Imo a statically-typed language is required to develop | maintainable code. Human communications, read documentation, is | much easier to extend than compilation-restrictions of a | programming language. | | What are the non-fixable downsizes, which prevent serious | adaptation of D? | _readsupuponthepostbecauseaCcomparsionwasspotted_ | | My personal opinion is: The convenience of tooling. Currently I | am developing a language agnostic language server, which aims to | be integrated in unix environmets without requiring exorbitant | memory (currently 8 MB + file-contents). I feel, that this is my | only contribution I can submit to the community iff I suceed. | SemanticStrengh wrote: | Let me takes this opportunity to explain that among the many | contraints of rust, it is the undertalked one about the absurd no | cast promotion from smaller integer (e.g. a char) to a bigger | integer that made me quit and save my sanity. Having to make | explicit casts a dozen times per functions for basic | manipulations of numbers on a grid (and the index type mismatch) | is an insult to the developer intelligence. It seems some people | are resilient and are able to write nonsensical parts of code | repeatedly but for me, I can't tolerate it. | josephg wrote: | I don't mind a few "as usize" casts because usually you can | cast once and be done with it. But the cast that kills me is | this one: | | How do you add an unsigned and a signed number together in | rust, in a way which is fast (no branches in release mode), | correct and which panics in debug mode in the right places (if | the addition over- or under-flows)? Nearly a year in to rust | and I'm still stumped! | steveklabnik wrote: | https://rust.godbolt.org/z/e377o5148 is the first thing I | thought of. | | You didn't specify sizes, or if you wanted the result to be | signed or unsigned, but "assume two's compliment wrapping in | release and panic in debug on over/underflow" is the default | behavior of +. | mjw1007 wrote: | That fails the "panics in debug mode in the right places" | requirement: | | https://play.rust- | lang.org/?version=stable&mode=debug&editio... | steveklabnik wrote: | Oh duh, yeah, my bad. I was tweaking stuff around and | lost that property. And seems like TryInto doesn't | compile away entirely. Boo. | | You can write your own debug_assert! though: | https://play.rust- | lang.org/?version=stable&mode=debug&editio... | | not as nice, but it does work. If you were doing this a | lot you could macro it up, impl as a method on all the | various types you want... a pain, but it is possible. | allisdust wrote: | Considering all the type casting bugs prevalent in other | languages, I would have more trust in the compiler than | programmers at this point. You can always pick javascript of | course, which happily returns you what ever it feels like. | Frankly this explicit casting makes the next developer's life | easier. | SemanticStrengh wrote: | completely off topic, a smaller type to a larger type can | never be an issue. | yencabulator wrote: | _When_ the invisible conversion happens changes the end | result. It can still be very tricky. | SemanticStrengh wrote: | E.g on function parameters. It's always pass by copy, | there can't be an issue. | voidhorse wrote: | I wholeheartedly agree that rust's syntax is way noisier and | uglier than I'd like, and it's nice to see someone else raise the | point seriously. People tend to act like syntax is an ancillary | detail in a language, but actually it's fundamental! It's our | direct interface into the language itself and if it's painful to | read and write the language won't be pleasant to use, no matter | how great it's semantics may be. | | Beyond the line noise problem. I feel some of rust's syntactic | choices are confusing. For instance: | | let x = 2 | | Introduces a new name and binds it to the value 2 while | | if let Some(x) = y | | Is a shorthand for pattern matching. Meanwhile other matching | structures have no need of "let" at all. Likewise this extends | the semantics of what "if" means and also overloads "=" (e.g, | glancing at this, would you say equals is binding a value to a | pattern, performing a Boolean check, or both?) Rust has a couple | of one-off weird syntactical devices that have been introduced as | shorthand that imo quickly increase the cognitive load required | to read code because several structures and keywords are reused | in slightly different ways to mean entirely different things. | | There are a lot of similar syntactic hoops around type signatures | because they didn't go with the old "type variables must be | lowercase" rule which leads to subtle potential ambiguities in | parsing T as a variable or proper type in some cases that thus | forces additional syntax on the user. | | I also think there are too many ways to express equivalent things | in Rust, which again leads to more cognitive overhead. Reading | the current docs, I get the sense the language is becoming "write | biased". Whenever they introduce some syntactic shortcut the | justification is to save typing and eliminate small amounts of | repetition, which is great in theory but now we have N ways of | writing and reading the same thing which quickly makes code hard | to grok efficiently imo. | | This minor gripe comes with the big caveat that it remains | probably the most interesting language to become vogue since | Haskell. | irishsultan wrote: | > For instance: | | > let x = 2 | | > Introduces a new name and binds it to the value 2 while | | > if let Some(x) = y | | > Is a shorthand for pattern matching. | | Both introduce a new name (x) and both pattern match, it's just | that the pattern in let x = 2 is simply match anything and | assign it the name x, you could just as well write | | let t@(x, y) = (2, 4); | | Which binds t to (2, 4), x to 2 and y to 4 and there it's | perhaps more clear that normal let is pattern matching as much | as if let is pattern matching. | burntsushi wrote: | It might help you to think of 'if let' as an extension of 'let' | rather than an extension of 'if'. That is, 'let' by itself | supports irrefutable patterns. e.g., let | std::ops::Range { start, end } = 5..10; | | So the 'if' is "just" allowing you to also write _refutable_ | patterns. | preseinger wrote: | That's fine but it's nonintuitive. | burntsushi wrote: | It is to me. | voidhorse wrote: | That is a useful way to think about it for sure, I'm mostly | using it as an illustration of what is probably a | philosophical difference between myself and the Rust | maintainers; in other words, I don't see why we need if let | when we already have match with _ wildcards. It's the sort of | syntactic shortcut that gives authors of code relatively | little benefit (save a few keystrokes) and readers of code | yet one more syntactic variation to contend with. | | I guess another way of putting it is that I think Rust has a | lot of sugar that's confusing. | | Kotlin is an example of a language that has a lot of similar | syntactic shortcuts and functional underpinnings that | implements them in a more readable and consistent fashion | imo. | burntsushi wrote: | I could live without 'if let'. I'm not a huge fan of it | either, although I do use it. | | Its most compelling benefit to me is not that it saves a | few keystrokes, but that it avoids an extra indentation | level. Compare (taking from a real example[1]): | if let Some(quits) = args.value_of_lossy("quit") { | for ch in quits.chars() { if !ch.is_ascii() | { anyhow::bail!("quit bytes must be | ASCII"); } // FIXME(MSRV): | use the 'TryFrom<char> for u8' impl once we are | // at Rust 1.59+. c = | c.quit(u8::try_from(u32::from(ch)).unwrap(), true); | } } | | with: match args.value_of_lossy("quit") { | None => {} Some(quits) => { for | ch in quits.chars() { if !ch.is_ascii() | { anyhow::bail!("quit bytes must be | ASCII"); } // | FIXME(MSRV): use the 'TryFrom<char> for u8' impl once we | are // at Rust 1.59+. | c = c.quit(u8::try_from(u32::from(ch)).unwrap(), true); | } } } | | The 'for' loop is indented one extra level in the latter | case. With that said, I do also use 'if let' because it | saves some keystrokes. Taking from another real example[2], | compare: if let Some(name) = | get_name(group_index) { write!(buf, "/{}", | name).unwrap(); } | | with match get_name(group_index) { | None => {} Some(name) => { | write!(buf, "/{}", name).unwrap(); } } | | (I could use '_ => {}' instead of 'None' to save a few | more.) | | I do find the 'if let' variant to be a bit easier to read. | It's optimizing for a particular and somewhat common case, | so it does of course overlap with 'match'. But I don't find | this particular overlap to be too bad. It's usually pretty | clear when to use one vs the other. | | But like I said, I could live without 'if let'. It is not a | major quality of life enhancement to me. Neither will its | impending extensions. i.e., 'if let pattern = foo && | some_booolean_condition {'. | | [1]: https://github.com/BurntSushi/regex- | automata/blob/fbae906823... | | [2]: https://github.com/BurntSushi/regex- | automata/blob/fbae906823... | saurik wrote: | I don't code in Rust--and thereby might be expected to | not know all of these patterns and want to have to learn | fewer bits--and yet I agree with you. I feel like | removing this "if let" variant would be similar to saying | we don't need if statements as they are equivalent to a | loop that ends in break. I actually even will say the if | let is much easier to read as with the match I have to | check why it is a match and verify it has the None case-- | similar to checking if a loop is really going to loop or | if it always ends in break--whereas I can skip all that | work if I see the "if". | beltsazar wrote: | > I feel some of rust's syntactic choices are confusing. For | instance: | | > let x = 2 | | > Introduces a new name and binds it to the value 2 while | | > if let Some(x) = y | | > Is a shorthand for pattern matching. | | It won't be as confusing once you realize that both do the same | thing: variable binding. The difference is that the former is | an irrefutable binding, whereas the latter is a refutable | binding. | | Suppose that we have: struct Foo(i32); | | A few more examples of irrefutable binding: | | 1. As a local variable: let Foo(x) = Foo(42); | | 2. As a function parameter: fn bar(Foo(x): | Foo) {} | ntoskrnl wrote: | I'm overall a rust fan but I've always agreed with you about | `if let`. What I don't like is that it reads right-to-left and | starts getting awkward if either side is much longer than just | a variable name. if let Some(Range { start, end | }) = self.calc_range(whatever, true) { // ... } | | I feel it would read much smoother if you switched the two | sides so execution flows left-to-right if | self.calc_range(whatever, true) is Some(Range { start, end }) { | // ... } | mpawelski wrote: | Agree, this is something that I wish was changed and it's | something that C# got right. I think I tried to look up why | this syntax was chosen and found some old github issues when | people were actually suggesting the latter syntax (pattern on | the right) and I think there were some syntax ambiguities in | this syntax. Not sure if this was the main reason. Maybe the | lang team just didn't thought the difference is important | enough (and it is for me! ;-)). C# lang designers think about | IDE experience when designing language syntax (that's why we | have "from", "where", "select" order in LINQ, for better IDE | code completion), hope other language designers were more | thoughtful about it too. | metaltyphoon wrote: | Agreed and that' how C# does pattern matching on `if` | avgcorrection wrote: | Conservative Java has something similar with try-with-resource | and the upcoming instanceof pattern matching. | ArdelleF wrote: | We do a lot of Rust compilation exploration during the | development of TiKV(github.com/tikv/tikv), a lot of interesting | learnings ... https://en.pingcap.com/blog/rust-huge-compilation- | units/ | SemanticStrengh wrote: | thanks for maintaining jemalloc :) | cmrdporcupine wrote: | Good article. I have some things to say, because that's what I | do. | | To start: I have to say that I find some of the comments here a | little odd -- the competition for Rust is not Go or TypeScript or | Kotlin or whatever. If you're using Rust in your full-stack | webdev world to serve, like, database queries to webpages or | whatever... I don't know why. Rust is clearly for things like: | writing an OS, writing a browser, writing a low latency high | throughput transaction server, writing a game. For the other | things I'd say there's plenty of other options. It's been years | since I worked in web applications, but I struggle to see the | need for Rust there. | | Rust is for the same niche that C++ and C sit in now. A similar | niche that Zig is targeting. I don't think D with its <admittedly | now optional> GC or Golang sit in this same space _at all_. Also, | having spent a year working in Go I don 't understand how anybody | could complain about Rust encouraging boilerplate but propose Go | with a straightface. Go (at least the Go I was working on at | Google) was just a pile of boilerplate. Awful. The syntax of the | language is... fine. Generics will fix most of my complaints with | it. The _culture_ around the language I found repulsive. | | Anways, for years (prior to C++-11) I whined about the state of | C++. Not just its lack of safety but the idiosyncracies of its | syntax and its lack of modern language features I was familiar | with from e.g. OCaml and from hanging out on Lambda The Ultimate. | By modern features I mean pattern matching & option / result | types, lambdas, type inference, and a generics/parameterized type | system which wasn't ... insane. Remember, this is pre-C++11. It | was awful. C++-11 and beyond addressed some concerns but not | others. And I actually really love writing in C++ these days, but | I'm still well aware that it is a dogs breakfast and full of foot | guns and oddities. I've just learned to think like it. | | Anyways, back to Rust...before C++11, when I saw Graydon Hoare | had kickstarted a project at Mozilla to make a systems | programming language (that is without a GC) that supported modern | language features I was super stoked. I tended to follow what | Graydon was doing because he's talented and he's a friend-of- | friends. Rust as described sounded like exactly what I wanted. | But the final delivery, with the complexities of the borrow | checker... are maybe something that I hadn't gambled on. Every | few months I give another wack at starting a project in Rust and | every few months I tend to run up against the borrow checker with | frustration. But I think I have it licked now, I think I will | write some Rust code in my time off work. | | So my personal take on Rust is this: on _paper_ it 's the fantasy | language I always wanted, but in _reality_ it has many of the | complexity warts that other people have pointed to. | | _However_ it is better than all the alternatives (other than | maybe Zig) in this space in many many ways. But _most | importantly_ it seems to have gained momentum especially in the | last 2-3 years. It seems clear to me now that the language will | have success. So I think systems developers will probably need to | learn and "love" it just like they do C/C++ now. And I don't | think that's a bad thing because I think a culture will build up | that will get people up to speed and some of the syntactical | oddities just won't look that odd anymore. And the world of | software dev will hopefully be a bit safer, and build systems | less crazy, and so on. | bilkow wrote: | It looks like I'm on the minority here, but I generally like | Rust's syntax and think it's pretty readable. | | Of course, when you use generics, lifetimes, closures, etc, all | on the same line it can become hard to read. But on my experience | on "high level" application code, it isn't usually like that. The | hardest thing to grep at first for me, coming from python, was | the :: for navigating namespaces/modules. | | I also find functional style a lot easier to read than Python, | because of chaining (dot notation) and the closure syntax. | | Python: array = [1, 0, 2, 3] new_array | = map( lambda x: x * 2, filter( | lambda x: x != 0, array ) ) | | Rust: let array = [1, 0, 2, 3]; let | new_vec: Vec<_> = array.into_iter() .filter(|&x| x != | 0) .map(|x| x * 2) .collect(); | | I mean, I kind of agree to the criticism, specially when it comes | to macros and lifetimes, but I also feel like that's more | applicable for low level code or code that uses lots of features | that just aren't available in e.g. C, Python or Go. | | Edit: Collected iterator into Vec | the__alchemist wrote: | I think part of this comes down to: Does your Rust code make | heavy use of generics? I find myself deliberately avoiding | generics and libraries that use them, due to the complexity | they add. Not just syntactic noise, but complicated APIs that | must be explicitly documented; rust Doc is ineffective with | documenting what arguments are accepted in functions and | structs that use generics. | | See also: Async. | klabb3 wrote: | > See also: Async. | | Ah, the good ole generic, nested, self-referencing, | unnameable state machine generator. | klodolph wrote: | There are people who write Python code like that, but it's an | extreme minority. Here's the more likely way: | array = [1, 0, 2, 3] new_array = [x * 2 for x in array | if x != 0] | | Just as a matter of style, few Python programmers will use | lambda outside something like this: array = | [...] arry.sort(key=lambda ...) | bilkow wrote: | I guess you're right, list/generator comprehensions are the | idiomatic way to filter and map in python, with the caveat of | needing to have it all in a single expression (the same goes | for lambda, actually). | | I still feel like chained methods are easier to | read/understand, but list comprehensions aren't that bad. | Iwan-Zotow wrote: | > with the caveat of needing to have it all in a single | expression (the same goes for lambda, actually). | | one could use multiple expressions in lambda in (modern) | Python | vgel wrote: | Do you mean using the walrus operator? Because unless I | missed a recent PEP, I don't know of a way to do this | without something hacky like that. | dralley wrote: | Even in Rust I don't like chains that go beyond ~4 | operations. At some point it becomes clearer when expressed | as a loop. | nemothekid wrote: | 1. I don't think your Python example if fair. I think | new_array = [x*2 for x in array if x != 0] | | is much more common. | | 2. In your example, `new_array` is an iterator; if you need to | transform that into an actual container, your rust code | becomes: let new_array = array.into_iter() | .filter(|&x| x != 0) .map(|x| x * 2) | .collect::<Vec<_>>(); | | And there your generic types rear their ugly head, compared to | the one liner in python. | saghm wrote: | I generally just write it like this: let | new_array: Vec<_> = array.into_iter() | .filter(|&x| x != 0) .map(|x| x * 2) | .collect(); | | I'm actually a bit confused by the `&x` given that | `into_iter()` is used, which would take ownership of the | array values, but assuming that it was supposed to be just | `iter()` (or that it's an array of &i32 or something I | guess), you're going to be copying the integer when | dereferencing, so I'd probably just use `Iterator::copied` if | I was worried about too many symbols being unreadable: | let new_array: Vec<_> = array.iter() .copied() | .filter(|x| x != 0) .map(|x| x * 2) | .collect(); | | There's also `Iterator::filter_map` to combine `filter` and | `map`, although that might end up seeming less readable to | some due to the need for an Option, and due to the laziness | of iterators, it will be collected in a single pass either | way: let new_array: Vec<_> = array.iter() | .copied() .filter_map(|x| if x == 0 { None } else | { Some(x * 2) }) .collect(); | | This is definitely more verbose than Python, but that's | because the syntax needs to disambiguate between owned and | copied values and account for static types (e.g. needing to | annotate to specify the return type of `collect`, since you | could be collecting into almost any collection type you | want). It's probably not possible to handle all those cases | with syntax as minimal as Python, but if you are fine with | not having fine-grained control over that, it's possible to | define that simpler syntax with a macro! There seem to be a | lot of these published so far | (https://crates.io/search?q=comprehension), but to pick one | that supports the exact same syntax in the Python example, | https://crates.io/crates/comprende seems to do the trick: | let array = [0, 1, 2, 3]; let new_array = c![x * 2 | for x in array if x != 0]; println!("{:?}", | new_array); // Prints [2, 4, 6] | | I'm not trying to argue that Rust is a 1:1 replacement to | Python or that if Python suits your needs, you shouldn't use | it; I think it's worth pointing out that Rust has more | complex syntax for a reason though, and that it has | surprisingly good support for syntactic sugar that lets you | trade some control for expressiveness that can alleviate some | of the pain you might otherwise run into. | bilkow wrote: | It actually needs the & in both my example and your second | example, because .filter receives a reference to the item | being iterated. Your second example doesn't compile: | https://play.rust- | lang.org/?version=stable&mode=debug&editio... | veber-alex wrote: | They maybe rear their ugly head but they also allow you to | collect the iterator into any collection written by you, by | the standard library or by any other crate. | | While in python you have list/dict/set/generator | comprehension and that's it. | nemothekid wrote: | I don't think it's bad thing. In fact one of my favorite | features is that you can do `.collect::<Result<Vec<_>, | _>>()` to turn an interators of Results, into a Result of | just the Vec if all items succeed or the first error. That | is a feature you just can't express in Python. | | But you have to admit that is a pretty noisy line that | could be difficult to parse. | dralley wrote: | Then don't write it that way. let | new_array: Vec<usize> = array.into_iter() | .filter(|&x| x != 0) .map(|x| x * 2) | .collect(); | | Isn't so bad. | nemothekid wrote: | I believe I have the habit of putting it on the end | because the final type might be different. Consider: | let array = ["DE", "AD", "BE", "EF"]; let | new_array: Vec<u32> = array.into_inter() | .map(|x| u32::from_str_radix(x, 16)) | .collect()?; | | In this case you need to specify the Result generic type | on generic. This has come up for me when working with | Stream combinators. Most projects probably end up in | needing some lifetime'd turbofish and you have to be able | to parse them. They aren't rare enough, IME, to argue | that Rust isn't noisy. | bilkow wrote: | Oh, yeah, you're right! If you want to collect into a Vec you | may need to specify the type, but usually, you can just call | `.collect()` and the compiler will infer the correct type (as | I suppose you're collecting it to use or return). | | If it can't infer, it's idiomatic to just give it a hint (no | need for turbofish): let new_vec: Vec<_> = | array.into_iter() .filter(|&x| x != 0) | .map(|x| x * 2) .collect(); | | I don't think that's ugly or unreadable. | | About the Python list comprehension, I answered your sibling, | I think you're both right but it also does have it's | limitations and that may be personal, but I find chained | methods easier to read/understand. | fmakunbound wrote: | > It's 2022 after all, and transistors are cheap: why don't all | our microcontrollers feature page-level memory protection like | their desktop counterparts? | | I always thought it was because of the added cost from increased | design complexity. Is it something else? | bunnie wrote: | Secretly, I suspect the answer is market differentiation. You | can charge a higher royalty for a CPU core that has an MMU, and | bundling it into the low end stuff erodes margins. | | The complexity is real, but in a typical SoC the actual CPU | core is maybe 10% of the area and tossing in an MMU impacts | maybe 1-2% of the total chip area. I haven't seen the pricing | sheets, but I suspect the much bigger cost is the higher | royalty payment associated with instantiating the MMU. ___________________________________________________________________ (page generated 2022-05-19 23:00 UTC)