[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)