[HN Gopher] Rust--: Rust without the borrow checker
___________________________________________________________________
Rust--: Rust without the borrow checker
Author : ravenical
Score : 113 points
Date : 2026-01-01 10:53 UTC (12 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| boxed wrote:
| A motivation section in the readme seems like it is needed.
| poly2it wrote:
| https://github.com/buyukakyuz/corroded/issues/11#issuecommen...
| corrode2711 wrote:
| Yes, that was my motivation.
| bhaney wrote:
| Are the compile times noticeably faster?
| worldsavior wrote:
| Probably not, because it seems like it still checks for errors
| but just suppresses them.
| misnome wrote:
| Even so, the borrow checker repeatedly profiles as an
| insignificant part of compile times, so wouldn't make a
| difference.
| throwawayffffas wrote:
| C++ with extra steps?
| corrode2711 wrote:
| C++ with a package manager.
| dorianniemiec wrote:
| Uh oh, this might look like a potentially memory-unsafe version
| of Rust...
| mkl95 wrote:
| Rust++ would be a nicer name then
| dorianniemiec wrote:
| Rust++? :)
| thushanfernando wrote:
| Bust?
| corrode2711 wrote:
| Bust++
| petcat wrote:
| [flagged]
| scott_w wrote:
| Honestly, I thought it was serious because I've seen people do
| things exactly like this, just in different languages.
|
| By "this" I mean "spend all their time fighting against the
| language/framework because they don't like it, rather than just
| picking a different language."
| eru wrote:
| There can be good reasons for choosing a language that you
| otherwise don't like.
|
| Eg legacy software, or because your boss tells you, or
| because of legal requirements, or because of library
| availability etc.
| scott_w wrote:
| Those are excellent reasons but then you shouldn't fight
| the language, you should go with the language/framework
| conventions as much as possible. Trying to fight the
| language design will only lead to buggy, hard to understand
| code, so either suck it up or get a different job.
|
| EDIT: That last sentence is a bit harsher than I intended.
| I'm trying to convey the importance of professionalism in
| our work and remembering the experience of working with
| people who couldn't do this brought back some bad memories!
| MangoToupe wrote:
| Certain people feel very emotional about the compilers and
| interpreters they use
|
| You couldn't pay me to work with them
| josephg wrote:
| Don't worry, they probably wouldn't want to work with you
| either.
|
| Some programmers think and care a lot about software
| correctness in a kind of mathematical way. Others just want
| to ship features and enjoy their lives. Both approaches are
| fine. They just don't necessarily mix super well.
|
| Some people like to tell you that diverse teams work better.
| Years ago I worked with someone who had a PhD in
| psychometrics. She said that's kind of a lie. If you actually
| look at the research it shows something more interesting. She
| said the research shows that having a diverse set of
| backgrounds makes a team perform better. But having a diverse
| set of values makes a team perform worse. It makes sense. If
| one person on the team wants to vibe code and someone else
| wants to make every line of code perfect, you're all in for a
| bad time.
| qsera wrote:
| There is a third kind. Those who want to have a lot of fun
| by using their imagination to come up with interesting ways
| build something, but in rust, the borrow checker often
| won't have any of it.
|
| In rust you have to learn and internalize lot of the non-
| intutive borrow checker reasoning to remain sane. If you
| remember to spend a fraction of that effort to remember the
| "unsafe" things you could end up doing in C, then I think
| most people would be fine.
|
| But rust enforces it, which is good for a small fraction of
| all software that is being written. But "Rust for
| everything!?"..Give me a fucking break!
| MangoToupe wrote:
| This persona is the heart and soul of the "weirdly
| emotional about languages" archetype along with ruby
| fanatics. Look, y'all have notable and significant value,
| but only in very specific and unusual circumstances
| corrode2711 wrote:
| And you were right.
| dang wrote:
| Could you please not post this sort of snarky-generic-meta
| comment? They attract upvotes and then stick at the top of the
| thread, choking out actually interesting discussion. (That's
| where this one was, but I'm going to mark it off topic and
| downweight it now.)
|
| I completely understand your frustration about how common
| shallow-indignant comments are. But it doesn't help to post
| shallow-indignant or snarky comments of your own about it - it
| just produces even more of the same, or worse.
|
| The way to combat shallow-indignant, predictable, tedious,
| etc., threads is to find something that you're genuinely
| curious and open about, and post from that place instead.
|
| https://news.ycombinator.com/newsguidelines.html
| fithisux wrote:
| This should be called trust, because it does view the developer
| as evil.
| fithisux wrote:
| I meant "it does not view"
| gspr wrote:
| Tangentially related: the opposite, Rust's borrow checker sans
| the compiler, is actually very useful. As far as I understand,
| the borrow checker is a significant part of the work of writing a
| Rust compiler. Therefore, having the official borrow checker
| available as a standalone program can make alternative compilers
| (e.g. for exotic hardware) feasible faster, because they won't
| need a borrow checker of their own from the get-go.
| bananaflag wrote:
| I get your point, but still you haven't identified a use for
| the borrow checker sans the compiler.
| tialaramex wrote:
| Why would this matter? The borrowck is (a) not needed during
| bring-up because as its name suggests it is merely a check, so
| going without it just means you can write nonsense and then
| unbounded undefined behaviour results, but (b) written entirely
| in Rust so you can just compile it with the rest of this
| "exotic hardware" Rust compiler you've built.
| gspr wrote:
| Yeah, you're right, I'm misremembering something here. Thanks
| for the correction.
| raluk wrote:
| What are protental issues with compiler, by just disabling borrow
| checker? If I recall correctly some compiler optimisations for
| rust can not be done in C/C++ because of restrictions implied by
| borrow checker.
| 0xdeafbeef wrote:
| Rust can set restricts to all pointers, because 1 mut xor many
| shared refs rule. Borrow checker empowers this.
| https://en.wikipedia.org/wiki/Restrict
| imtringued wrote:
| The crazy part about this is that (auto) vectorization in
| Rust looks something like this:
| iter.chunks(32).map(vectorized)
|
| Where the vectorized function checks if the chunk has length
| 32, if yes run the algorithm, else run the algorithm.
|
| The compiler knows that the chunk has a fixed size at compile
| time in the first block, which means it can now attempt to
| vectorize the algorithm with a SIMD size of 32. The else
| block handles the scalar case, where the chunk is smaller
| than 32.
| vanviegen wrote:
| Without the borrow checker, how should memory be managed? Just
| never deallocate?
| flohofwoe wrote:
| It would be the same as in any language with manual memory
| management, you'd simply get a dangling pointer access. The
| 'move-by-default' semantics of Rust just makes this a lot
| trickier than in a 'copy-by-default' language though.
|
| It's actually interesting to me that the Rust borrow checker
| can 'simply' be disabled (e.g. no language- or stdlib-
| features really depending on the borrow checker pass) - not
| that it's very useful in practice though.
| masklinn wrote:
| The borrow checker does not deal with ownership, which is
| what rust's memory management leverages. The borrow checker
| validates that borrows (references) are valid aka that they
| don't outlive their sources and that exclusive borrows don't
| overlap.
|
| The borrow checker does not influence codegen at all.
| eptcyka wrote:
| The same as C++, destructors get called when an object goes
| out of scope.
| nineteen999 wrote:
| Love the "Note for LLMs" and the NSFW license.
| user3939382 wrote:
| Rust- is you use C with ring buffers. If you think you need
| dynamic memory allocation your program is underspecified.
| oskarbh7 wrote:
| How does "zero dynamic allocation" work in practice for
| something like a text editor IE. vscode or other apps that let
| users open arbitrary files?
| lpcvoid wrote:
| Just impose a maximum buffer size ;)
| Const-me wrote:
| It's technically possible to do, just very complicated and
| hard. Quite often, prohibitively so.
|
| Still, the main idea is despite the input files are
| arbitrarily large, you don't need an entire file in memory
| because displays aren't remotely large enough to render a
| megabyte of text. Technically, you can only load a visible
| portion of the input file, and stream from/to disk when user
| scrolls. Furthermore, if you own the file format, you can
| design it in a way which allowing editing without overwriting
| the entire file: mark deleted portions without moving
| subsequent content, write inserts to the end of files, maybe
| organize the file as a B+ tree, etc.
|
| That's how software like Word 97 supported editing of
| documents much larger than available memory. As you can
| imagine, the complexity of such file format, and the software
| handling them, was overwhelming. Which is why software
| developers stopped doing things like that as soon as
| computers gained enough memory to keep entire documents, and
| instead serialize them into sane formats like zipped XMLs in
| case of modern MS office.
| eru wrote:
| What if you don't know ahead of time how big that monitor
| is that you are displaying stuff on?
|
| In any case, what you are describing sounds like an ad-hoc
| re-implementation of virtual memory?
| Const-me wrote:
| > What if you don't know ahead of time how big that
| monitor is that you are displaying stuff on?
|
| Use a reasonable upper estimate?
|
| > ad-hoc re-implementation of virtual memory?
|
| If you rely on actual virtual memory instead of specially
| designed file format, saving large files will become
| prohibitively slow. On each save you have to stream the
| entire document from page file to actual memory,
| serialize the document, produce the entire file, then
| replace. And then when resuming editing after the save,
| you probably have to load the visible portion back from
| disk.
| 1718627440 wrote:
| Either take the biggest one or render in chunks.
| mrits wrote:
| Instead of over specifying a program you can just use dynamic
| memory allocation
| rcxdude wrote:
| Avoiding dynamic allocation does not avoid memory unsafety in
| C.
| throwawayffffas wrote:
| It would be great if it only allowed multiple mutable borrows.
| That's the only one that always bugs me, for mostly innocuous
| stuff.
| threethirtytwo wrote:
| This isn't actually unsafe unless shared across threads right?
| Maybe the borrow checker needs to be more nuanced to
| differentiate this rather then outright banning it all
| together. It would increase the logic of the borrow checker by
| a lot though.
| xlii wrote:
| > In addition to meeting the Open Source Definition, the
| following standards apply to new licenses: > (...) The
| license does not have terms that structurally put the licensor in
| a more favored position than any licensee.
| https://opensource.org/licenses/review-process
|
| That's a funfact I learned from IP lawyer when discussing
| possibility of open-source but otherwise LLVM-extempt license. If
| there is extemption (even in LLM) such license is most likely
| OSI-incompatible.
| w4rh4wk5 wrote:
| I am wondering whether this would actually be a helpful compile
| option in upstream rustc for quick prototyping. I don't want prod
| code to use this, but if I want to try things out during
| development, this could substantially shorten the dev cycle.
| 0xdeafbeef wrote:
| What the point, though? You will get compiling code, but later
| you would need to reachitecture code to avoid violating rust
| rules.
| withinboredom wrote:
| Sometimes, you just need to know if an idea will even work or
| what it would look like. If you have to refactor half the
| codebase (true story for me once), it makes the change a much
| harder sell without showing some benefits. IE, it keeps you
| from discovering better optimizations because you have to pay
| the costs upfront.
| eru wrote:
| Can't you usually just throw some quick referenced counted
| cells in there, to make the borrow checker happy enough for
| a prototype without refactoring the whole code base?
| LoganDark wrote:
| In Rust, it's a lot easier to refactor half the codebase
| than it would be in another language. Once you're done
| fighting the compiler, you're usually done! instead of
| NEVER being sure if you did enough testing.
| withinboredom wrote:
| I can't tell if you missed the whole point of
| "exploratory"...
| aw1621107 wrote:
| > Sometimes, you just need to know if an idea will even
| work or what it would look like.
|
| I think what GP is trying to say is that the value of such
| exploration might be limited if you end up with something
| incompatible with "proper" Rust anyways.
|
| I suppose it depends on how frequently "transition through
| invalid Rust while experimenting and end up with valid
| Rust" happens instead of "transition through invalid Rust
| while experimenting and end up with invalid Rust", as well
| as how hard it is to fix the invalid Rust in the latter
| case.
| Philpax wrote:
| After a while, you just don't write code that would cause
| substantial borrow-checker problems, even when prototyping. I'd
| say the slow compile times are much more of an impediment for a
| practicing Rust prototyper than the borrow checker.
| ismailmaj wrote:
| undefined behavior on steroids be like:
| hacker_homie wrote:
| I wish I could make the borrow checker give warnings not errors.
| It would make exploration so much easier, so I don't have to
| fight the borrow checker until I know how to build what I want.
| hoppp wrote:
| Then you have code full of warnings and undefined behavior?
|
| I think fighting the borrow checker is more like a rite of
| passage. Rust is not my favorite language but the borrow
| checker is great.
| leoh wrote:
| This is not a hacker's take
| hoppp wrote:
| I'm lazy. If you turn off the borrow checker the code will
| need a rewrite later, since it's there for a very good
| reason.
| dataflow wrote:
| This can't possibly be guaranteed to work just by disabling the
| checker, can it? If Rust optimizes based on borrow-checker
| assumptions (which I understand it can and does) then wouldn't
| violating them be UB, unless you also mess with the compiler to
| disable those optimizations?
| tialaramex wrote:
| If you write correct Rust code it'll work, the borrowck is just
| that, a check, if the teacher doesn't check your homework where
| you wrote that 10 + 5 = 15 it's still correct. If you write
| incorrect code where you break Rust's borrowing rules it'll
| have unbounded Undefined Behaviour, unlike the actual Rust
| where that'd be an error this thing will just give you broken
| garbage, exactly like a C++ compiler.
|
| Evidently millions of people _want_ broken garbage, Herb Sutter
| even wrote a piece celebrating how many more C++ programmers
| and projects there were last year, churning out yet more broken
| garbage, it 's a metaphor for 2025 I guess.
| ozgrakkurt wrote:
| I have been using kde for years now without a single problem.
| Calling cpp garbage sounds wrong.
| LtWorf wrote:
| People who can't do something, sometimes assume nobody else
| possibly could.
| zzrrt wrote:
| I'm sure some people could tiptoe through minefields
| daily for years, until they fail. Nobody is perfect at
| real or metaphorical minefields, and hubris is probably
| the only reason to scoff at people suggesting
| alternatives.
| 3836293648 wrote:
| People hate C because it's hard, people hate C++ because
| it truly is rubbish. Rubbish that deserved to be tried
| but that we've now learned was a mistake and should move
| on from.
| doodlesdev wrote:
| KDE is a great desktop environment , but it's also
| notorious for being a buggy and unpolished DE [1]. It's
| good your experience wasn't like that, but it's certainly
| not how the software is generally perceived.
|
| [1]: Of course, different versions have different levels of
| stability. Also, some of these bugs and problems wouldn't
| be prevented by using an alternative language such as Rust.
| danudey wrote:
| Well FWIW, the original poster's anti-C++ statements aside,
| removing the borrow checker does nothing except allow you
| to write thread-unsafe (or race condition-unsafe) code.
| Therefore, the only change this really makes is allowing
| you to write slightly more ergonomic code that could well
| break somewhere at some point in time unexpectedly.
| amelius wrote:
| People don't want garbage. But in any case, they don't want
| straightjackets like the borrow checker.
|
| Hence, they use GC'd languages like Go whenever they can.
| eru wrote:
| Straightjackets can be very useful.
|
| Haskell (and OCaml etc) give you both straightjackets and a
| garbage collector. Straightjackets and GC are very
| compatible.
|
| Compared to C, which has neither straightjackets nor a GC
| (at least not by default).
| reactordev wrote:
| >Straitjackets can be very useful.
|
| Only if you're insane.
| qsera wrote:
| Damn! This is the funniest HN comment that I have ever
| come across...
| josephg wrote:
| How dare you. C is a fine language.
|
| Just don't accidentally step on any of these landmines
| and we'll all get along great.
| reactordev wrote:
| Not to mention your sidearm is a Sig P365. We like to
| call them footguns.
| imtringued wrote:
| The meaning of straightjacket here is inherently
| subjective and not to be meant literally.
| qsera wrote:
| >Haskell (and OCaml etc) give you both straightjackets..
|
| Haskell's thing with purity and IO does not feel like
| that. In fact Haskell does it right (IO type is reflected
| in type). And rust messed it up ("safety" does not show
| up in types).
|
| You want a global mutable thing in Haskell? just use
| something like an `IORef` and that is it. It does not
| involve any complicated type magic. But mutations to it
| will only happen in IO, and thus will be reflected in
| types. That is how you do it. That is how it does not
| feel like a straight jacket.
|
| Haskell as a language is tiny. But Rust is really huge,
| with endless behavior and expectation to keep in mind,
| for some some idea of safety that only matter for a small
| fraction of the programs.
|
| And that I why I find that comment very funny. Always
| using rust is like always wearing something that
| constrains you greatly for some idea of "safety" even
| when it does not really matter. That is insane..
| gpm wrote:
| > "safety" does not show up in types
|
| It does in rust. An `unsafe fn()` is a different type
| than a (implicitly safe by the lack of keyword) `fn()`.
|
| The difference is that unsafe fn's can be encapsulated in
| safe wrappers, where as IO functions sort of
| fundamentally can't be encapsulated in non-IO wrappers.
| This makes the IO tagged type signatures viral throughout
| your program (and as a result annoying), while the safety
| tagged type signatures are things you only have to think
| about if you're touching the non-encapsulated unsafe code
| yourself.
| qsera wrote:
| >The difference is that unsafe fn's can be encapsulated
| in safe wrappers
|
| This is the koolaid I am not willing to drink.
|
| If you can add safety very carefully on top of unsafe
| stuff (without any help from compiler), why not just use
| `c` and add safety by just being very careful?
|
| > IO tagged type signatures viral throughout your program
| (and as a result annoying)..
|
| Well, that is what good type systems do. Carry
| information about the types "virally". Anything short is
| a flawed system.
| gpm wrote:
| > This is the koolaid I am not willing to drink.
|
| > If you can add safety very carefully on top of unsafe
| stuff (without any help from compiler), why not just use
| `c` and add safety by just being very careful?
|
| There is help from the compiler - the compiler lets the
| safe code expose an interface that creates strict
| requirements about how it is being called with and
| interacted with. The C language isn't expressive enough
| to define the same safe interface and have the compiler
| check it.
|
| You can absolutely write the _unsafe_ part in C. Rust is
| as good at encapsulating C into a safe rust interface as
| it is at encapsulating unsafe-rust into a safe rust
| interface. Just about every non-embedded rust program
| depends on C code encapsulated in this manner.
|
| > Well, that is what good type systems do. Carry
| information about the types "virally". Anything short is
| a flawed system.
|
| Good type systems describe the interface, not every
| implementation detail. Virality is the consequence of
| implementation details showing up in the interface.
|
| Good type systems minimize the amount of work needed to
| use them.
|
| IO is arguably part of the interface, but without further
| description of what IO it's a pretty useless detail of
| the interface. Meanwhile exposing a viral detail like
| this as part of the type system results in lots of work.
| It's a tradeoff that I think is generally not worth it.
| qsera wrote:
| >the compiler lets the safe code expose an interface that
| creates strict requirements about how it is being called
| with and interacted with..
|
| The compiler does not and cannot check if these strict
| requirements are enough for the intended "safety". Right?
| It is the judgement of the programmer.
|
| And what is stopping a `c` function with such
| requirements to be wrapped in some code that actually
| checks these requirements are met? The only thing that
| the rust compiler enables is to include a feature to mark
| a specific function as unsafe.
|
| In both cases there is zero help from the compiler to
| actually verify that the checks that are done on top are
| sufficient.
|
| And if you want to mark a `c` function as unsafe, just
| follow some naming convention...
|
| >but without further description of what IO it's a pretty
| useless detail of the interface..
|
| Take a look at effect-system libraries which can actually
| encode "What IO" at the type level and make it available
| everywhere. It is a pretty basic and widely used thing.
| gpm wrote:
| > The compiler does not and cannot check if these strict
| requirements are enough for the intended "safety". Right?
| It is the judgement of the programmer.
|
| Yes*. It's up to the programmer to check that the safe
| abstraction they create around unsafe code guarantees all
| the requirements the unsafe code needs are upheld. The
| point is that that's done once, and then all the safe
| code using that safe abstraction can't possibly fail to
| meet those requirements - or in other words any safety
| related bug is always in the relatively small amount of
| code that uses unsafe and builds those safe abstraction.
|
| > And what is stopping a `c` function with such
| requirements to be wrapped in some code that [doesn't]
| actually checks these requirements are met?
|
| Assuming my edit to your comment is correct - nothing.
| It's merely the case that any such bug would be in the
| small amount of clearly labelled (with the unsafe
| keyword) binding code instead of "anywhere".
|
| > The only thing that the rust compiler enables is to
| include a feature to mark a specific function as unsafe.
|
| No, the rust compiler has a lot more features than just a
| way to mark specific functions as unsafe. The borrow
| checker, and it's associated lifetime constraints,
| enforcing that variables that are moved out of (and
| aren't `Copy`) aren't used, is one obvious example.
|
| Another example is marking how data can be used across
| threads with traits like `Send` and `Sync`. Another -
| when compared to C anyways - is simply having a
| visibility system so that you can create structs with
| fields that aren't directly accessible via other code (so
| you can control every single function that directly
| accesses them and maintain invariants in those
| functions).
|
| > In both cases there is zero help from the compiler to
| actually verify that the checks that are done on top are
| sufficient.
|
| Yes and no, "unsafe" in rust is synonymous with "the
| compiler isn't able to verify this for you". Typically
| rust docs do a pretty good job of enumerating exactly
| what the programmer must verify. There are tools that try
| to _help_ the programmer do this, from simple things like
| being able to enable a lint that checks every time you
| wrote unsafe you left a comment saying why it 's ok, and
| that you actually wrote something the compiler couldn't
| verify in the first place. To complex things like having
| a (very slow) interpreter that carefully checks that in
| at least one specific execution every required invariant
| is maintained (with the exception of some FFI stuff that
| it fails on as it is unable to see across language
| boundaries sufficiently well).
|
| The rust ecosystem is very interested in tools that make
| it easier to write correct unsafe code. It's just rather
| fundamentally a hard problem.
|
| * Technically there are very experimental proof systems
| that can check some cases these days. But I wouldn't say
| they are ready for prime time use yet.
| elbear wrote:
| When I started learning Haskell, it did feel like coding
| with a straightjacket.
| qsera wrote:
| I think that is because when you start learning Haskell,
| you are not typically told about state monads, `IORefs`
| and likes that enables safe mutability.
|
| It might be because Monads could have a tad bit advanced
| type machinery. But IORefs are straightforward, but
| typically one does not come across it until a bit too
| late into their Haskell journey.
| 127 wrote:
| You call it a straightjacket, I call it a railroad track
| for reliably delivering software.
| jjgreen wrote:
| It is possible to like something without hating people who
| like something else, can't people just live and let live?
| tialaramex wrote:
| Did I write that I hated somebody? I don't think I wrote
| anything of the sort. I can't say my thoughts about Bjarne
| for example rise to hatred, nobody should have humoured him
| in the 1980s, but we're not talking about what happened
| when rich idiots humoured The Donald or something as
| serious as that - nobody died, we just got a lot of
| software written in a crap programming language, I've had
| worse Thursdays.
|
| And although of course things could have been better they
| could also have been worse. C++ drinks too much OO kool
| aid, but hey it introduced lots of people to generic
| programming which is good.
| jjgreen wrote:
| Correct me if I'm wrong, but I don't think you think that
| C++ programmers actually _want_ to write "broken
| garbage", so when you say "millions of people _want_
| broken garbage " the implication is that a) they do write
| broken garbage, b) they're so stupid don't even know that
| is what they are doing. I can't really read else than in
| the same vein as an apartheid-era white South-African
| statement starting "all blacks ...", i.e., an insult to a
| large class of people simply for their membership in that
| class. Maybe that's not your intent, but that's how it
| reads to me, sorry.
| dminik wrote:
| Considering how many people will defend C++ compilers
| bending over backwards to exploit some accidental
| undefined behaviour with "but it's fast though" then
| yeah, that's not an inaccurate assessment.
| tialaramex wrote:
| I can't help how you feel about it, but what I see is
| people who supposedly "don't want" something to happen
| and yet take little or no concrete action to prevent it.
| When it comes to their memory safety problem WG21 talks
| about how they want to address the problem but won't take
| appropriate steps. Years of conference talks about
| safety, and C++ 26 is going to... encourage tool vendors
| to diagnose some common mistakes. Safe C++ was rejected,
| and indeed Herb had WG21 write a new "standing rule"
| which imagines into existence principles for the language
| that in effect forbid any such change.
|
| Think Republican Senators offering thoughts and prayers
| after a school shooting, rather than Apartheid era white
| South Africans.
| 3836293648 wrote:
| Are you seriously comparing discrimination based on
| factors noone can control to a group literally defined by
| a choice they made? And you think that's a good faith
| argument?
| ada0000 wrote:
| herb sutter and the c++ community as a whole have put a lot
| of energy into improving the language and reducing UB; this
| has been a primary focus of C++26. they are not encouraging
| people to "churn out more broken garbage", they are
| encouraging people to write better code in the language they
| have spent years developing libraries and expertise in.
| lordgroff wrote:
| And for which there's often no serious alternative to in
| many domains anyway.
| ada0000 wrote:
| even when there are alternatives, sometimes it makes
| sense to use a library like Qt in its native language
| with its native documentation rather than a binding - if
| you can do so safely
| nemetroid wrote:
| Yes, many or even most domains where C++ sees a large
| market share are domains with no other serious
| alternative. But this is an indictment of C++ and not
| praise. What it tells us is that when there are other
| viable options, C++ is rarely chosen.
|
| The number of such domains has gone down over time, and
| will probably continue to do so.
| pron wrote:
| The number of domains where low-level languages are
| required, and that includes C, C++, Rust, and Zig, has
| gone down over time and continues to do so. All of these
| languages are rarely chosen when there are viable
| alternatives (and I say "rarely" taking into account
| total number of lines of code, not necessarily number of
| projects). Nevertheless, there are still some very
| important domains where such languages are needed, and
| Rust's adoption rate is low enough to suggest serious
| problems with it, too. When language X offers significant
| advantages over language Y, its adoption compared to Y is
| usually quite fast (which is why most languages get close
| to their peak adoption relatively quickly, i.e. within
| about a decade).
|
| If we ignore external factors like experience and
| ecosystem size, Rust is a better language than C++, but
| not better enough to justify faster adoption, which is
| exactly what we're seeing. It's certainly gained some
| sort of foothold, but as it's already quite old, it's
| doubtful it will ever be as popular as C++ is now, let
| alone in its heydey. To get there, Rust's market share
| will need to grow by about a factor of 10 compared to
| what it is now, and while that's possible, if it does
| that it will have been the first language to ever do so
| at such an advanced age.
| lordgroff wrote:
| The attitude expressed here and that tends to surface in any
| Rust discussion is the reason I completely lost interest in
| the language.
| tempodox wrote:
| You're expressing the same attitude here, just in reverse.
| Some users not thinking highly of C++ doesn't make Rust a
| worse or less interesting language.
| maxbond wrote:
| Rust isn't a one true language, no one necessarily needs to
| learn it, and I'm sure your preffered language is
| excellent. C and C++ are critical languages with legitimate
| advantages and use cases. Don't learn Rust of you aren't
| interested.
|
| But Rust, its community, and language flame wars are
| separate concerns. When I talk shop with other Rust people,
| we talk about our projects, not about hating C++.
| Maxatar wrote:
| So don't use it. Rust is not intended to be used by
| everyone. If you are happy using your current set of tools
| and find yourself productive with them then by all means be
| happy with it.
| pron wrote:
| For all its faults, and it has many (though Rust shares most
| of them), few programming languages have yielded more value
| than C++. Maybe only C and Java. Calling C++ software
| "garbage" is a bonkers exaggeration and a wildly distorted
| view of the state of software.
| Spivak wrote:
| How are we still having the same trade off discussion being
| argued so black and white when reality has shown that both
| options are preferred by different groups.
|
| Rust says that all incorrect programs (in terms of memory
| safety) are invalid but the trade is that some correct
| programs will also be marked as invalid because the compiler
| can't prove them correct.
|
| C++ says that all correct programs are valid but the trade is
| that some incorrect programs are also valid.
|
| You see the same trade being made with various type systems
| and people still debate about it but ultimately accept that
| they're both valid and not garbage.
| Maxatar wrote:
| >C++ says that all correct programs are valid but the trade
| is that some incorrect programs are also valid.
|
| C++ does not say this, in fact no statically typed
| programming language says this, they all reject programs
| that could in principle be correct but get rejected because
| of some property of the type system.
|
| You are trying to present a false dichotomy that simply
| does not exist and ignoring the many nuances and trade-offs
| that exist among these (and other) languages.
| tialaramex wrote:
| Nope. C++ really does deliberately require that compilers
| will in some cases emit a program which does... something
| even though what you wrote isn't a C++ program.
|
| Yes, that's very stupid, but they did it with eyes open,
| it's not a mistake. In the C++ ISO document the words
| you're looking are roughly (exact phrasing varies from
| one clause to another) Ill-formed No Diagnostic Required
| (abbreviated as IFNDR).
|
| What this means is that these programs are Ill-formed
| (not C++ programs) but they compile anyway (No diagnostic
| is required - a diagnostic would be an error or warning).
|
| Why do this? Well because of Rice's Theorem. They want a
| lot of tricky semantic requirements for their language
| but Rice showed (back in like 1950) that all the non-
| trivial semantic requirements are Undecidable. So it's
| impossible for the compiler to correctly diagnose these
| for all cases. Now, you could (and Rust does) choose to
| say if we're not sure we'll reject the program. But C++
| chose the exact opposite path.
| Maxatar wrote:
| I'm not sure what your replying to, but it can't be my
| comment because what you're saying has absolutely nothing
| to do with it.
|
| But kudos to you on writing an irrelevant wall of text.
| 1718627440 wrote:
| It does. The UB is false positives to the question "Is
| this a valid program".
| Maxatar wrote:
| No one disputes that C++ accepts some invalid programs, I
| never claimed otherwise. I said that C++'s type system
| will reject _some_ programs that are in principle
| correct, as opposed to what Spivak originally claimed
| about C++ accepting all correct programs as valid.
|
| The fact that some people can only think in terms of all
| or nothing is really saying a lot about the quality of
| discourse on this topic. There is a huge middle ground
| here and difficult trade-offs that C++ and Rust make.
| Spivak wrote:
| I knew I should have also put the (in terms of memory
| safety) on the C++ paragraph but I held off because I
| thought it would be obvious both talking about the borrow
| checker and in contrast to Rust with the borrow checker.
|
| Yes, when it comes to types C++ will reject theoretically
| sound programs that don't type correctly. And different
| type system "strengths" tune themselves to how many
| correct programs they're willing to reject in order to
| accept fewer incorrect ones.
|
| I don't mean to make it a dichotomy at all, every
| "checker", linter, static analysis tool--they all seek to
| invalidate some correct programs which hopefully isn't
| too much of a burden to the programmer but in trade
| invalidate a much much larger set of incorrect programs.
| So full agreement that there's a lot of nuance as well as
| a lot of opinions when it goes too far or not far enough.
| MangoToupe wrote:
| > If Rust optimizes based on borrow-checker assumptions
|
| This is a binary assumption that you can understand to evaluate
| to "true" in the absence of a borrow checker. If it is "false"
| it halts the compiler
| CGamesPlay wrote:
| Yes. An analog would be uninitialized memory. The compiler is
| free to make optimizations that assume that uninitialized
| memory holds every value and no value simultaneously (because
| it is undefined behavior to ever read it).
|
| In the following example, z is dereferenced one time and
| assigned to both x and y, but if z and x are aliased, then this
| is an invalid optimization. fn
| increment_by(x: &mut i32, y: &mut i32, z: &i32) {
| *x = *z; *y = *z; }
|
| https://rust.godbolt.org/z/Mc6fvTzPG
| masklinn wrote:
| > This can't possibly be guaranteed to work just by disabling
| the checker, can it?
|
| It works in the sense that the borrow checker stops bothering
| you and the compiler will compile your code. It will even work
| fine as long as you don't write code which invokes UB (which
| does include code which would not pass the borrow checker, as
| the borrow checker necessarily rejects valid programs in order
| to forbid all invalid programs).
| dataflow wrote:
| > It will even work fine as long as you don't write code
| which invokes UB (which does include code which would not
| pass the borrow checker, as the borrow checker necessarily
| rejects valid programs in order to forbid all invalid
| programs).
|
| To be clear, by "this" I meant "[allowing] code that would
| normally violate Rust's borrowing rules to compile and run
| successfully," which both of us seem to believe to be UB.
| masklinn wrote:
| Not quite, there _is_ code which fails borrow checking but
| is safe and sound.
|
| That is part of why a number of people have been waiting
| for Polonius and / or the tree borrows model, most classic
| are relatively trivial cases of "check then update" which
| fail to borrow check but are obviously non-problematic e.g.
| pub fn get_or_insert ( map: &'_ mut
| HashMap<u32, String>, ) -> &'_ String {
| if let Some(v) = map.get(&22) { return v;
| } map.insert(22, String::from("hi"));
| &map[&22] }
|
| Though ultimately even if either or both efforts bear
| fruits they will still reject programs which are well
| formed: that is the halting problem, a compiler can
| _either_ reject all invalid programs or accept all valid
| programs, but it can not do both, and the former is
| generally considered more valuable, so in order to reject
| all invalid programs compilers will necessarily reject some
| valid programs.
| Sytten wrote:
| Correct, I was reading a very interesting blog post [1] on how
| the rust compiler will change the LLVM annotaions like sending
| noalias for mutable pointer. This changes a lot the generated
| machine code. Disabling the borrow checker won't enable those
| LLVM flags.
|
| [1] https://lukefleed.xyz/posts/who-owns-the-memory-pt1/
| jokoon wrote:
| To me it feels like rust is barely readable sometimes. When I
| read some rust cost, I am often incapable to guess what it does,
| so it does not feel intuitive.
|
| I wish they made something simpler. At least C and C++ have a low
| barrier of entry and any beginner can write code.
|
| I don't think the borrow checker forced rust to be such a
| complicated language.
| mentalgear wrote:
| I can just second that. Maybe someone (or some LLM) can write a
| nice superset of Rust that is more readable - so the barrier of
| entry drops significantly and we can all write better, more
| efficient and memory-safe code!
| torginus wrote:
| I feel exactly the same - C++ might be a much more complex and
| arcane language when you consider its entire feature set, and
| all the syntactic machinery (I figured out by looking at STL or
| Boost code, just how much of C++ I don't know or understand),
| you can choose to not engage with most of the language. Hell,
| even stuff like unique_ptr is optional when you're just
| starting out.
|
| But with Rust, you have to understand almost all of the
| language very intimately to be a productive programmer, and
| Rust is not that great at hiding complexity, as in fairly
| innocious decisions often have far-reaching consequences down
| the line.
| mrits wrote:
| I've shipped a lot of Rust software without the understanding
| or even attempting to learn a lot of the language. There is
| plenty of things in core libraries around traits that I have
| no idea how they work or really care.
| drogus wrote:
| > you have to understand almost all of the language very
| intimately to be a productive programmer,
|
| I've seen absolute Rust noobs write production code in Rust,
| I have no idea where did you get that notion from. Most of
| the apps I've written or I've worked with don't even need to
| use explicit lifetimes at all. If you don't need absolute
| performance with almost none memory allocations, it's
| honestly not rocket science. Even more so if you're writing
| web backends. Then the code doesn't really differ that much
| from Go.
| sesm wrote:
| C++ doesn't have low barrier of entry, I almost quit
| programming as a teen because of C++.
| torginus wrote:
| Imo the worst thing about starting out with C++ (which is
| much better with Rust), is the lack of credible package
| management/build system that allows you to just install
| packages.
|
| This used to be even more true previously than today.
| Nowadays, there's stuff like vcpkg, and tons of resources,
| but I still wouldn't call it straightforward compared to
| something like nuget or cargo.
|
| It tooke me more time to figure out CMake than entire other
| programming languages.
| tialaramex wrote:
| It does really help, in modern languages where they provide
| tools in the box and the ecosystem just accepts those as
| the default+ tools, to have the default be that when you
| make a new project it just works, often by having it print
| "Hello, World!" or something else simple but definitive as
| proof we made a program.
|
| + Default means just that, neither Rust's own compiler nor
| the Linux kernel need the cargo tooling, but these projects
| both have _actual toolsmiths_ to maintain their build
| infrastructure and your toy program does not. There should
| be a default which Just Works at this small scale.
| 1718627440 wrote:
| > the lack of credible package management
|
| APT/dpkg/yast/rpm/pacman/... ?
|
| Make is very simple, you don't even need a makefile. Just
| type "make main" for main.cpp and it works.
| tialaramex wrote:
| There's a weird cognitive bias where somehow people justify
| "I compiled this Hello World C++ project " as "C++ is easy"
| and yet "I wasn't able to understand how this optimized
| linear algebra library works" gets classed as "Rust is hard".
|
| In reality it matters what you already know, and whether you
| want to understand deeply or are just interested in enough
| surface understanding to write software. There's a reason C++
| has an entire _book_ about its many, many types of
| initialization for example.
| vanviegen wrote:
| Yes, Rust has a pretty steep learning curve. If you're not
| writing very low level stuff and don't need to squeeze out
| every last bit of performance, there are many other, simpler
| languages to choose from.
|
| I think we may safely assume that Rust's designers are smart
| people that have made every effort to keep Rust as simple as it
| can be, given its intended use.
| estebank wrote:
| If you're not writing very low level stuff and don't need to
| squeeze out every last bit of performance, Rust code can be
| very simple and easy to understand as well.
| Someone1234 wrote:
| > At least C and C++ have a low barrier of entry and any
| beginner can write code.
|
| C/C++ is great at giving that false sense of competence. Then
| suddenly you're getting a segfault, and you'll never determine
| why with beginner knowledge, since the crash-line and the
| mistake-line aren't even in the same zipcode (and or same Git
| changeset).
|
| Rust forces you to not "skip" knowledge steps. If you have a
| gap in your knowledge/understanding the compiler will call you
| out immediately. C/C++ will happily let your dangerously bad
| code compile and kinda-run, until it doesn't.
|
| I'm not anti-C/C++, I've actually written tons. I love C in
| particular. But saying that they're beginner-friendly feels
| wrong, a lot of people quit the language because "random stuff"
| starts to go wrong, and they lack the knowledge to determine
| _why_.
| josephg wrote:
| Yep. I've heard it said that Rust forces you to experience
| all the pain up front. C will happily compile very broken
| code.
|
| One of my formative memories learning C came after I wrote a
| function which accidentally returned a pointer to a variable
| on the stack. It took me about a week to track that bug down.
| I found it eventually - and then realised the compiler had
| been warning me about it the whole time. I'd just been
| ignoring the warnings "while I got my code working". Ugh. The
| rust borrow checker wouldn't let you even compile code like
| that.
|
| If you're going to be working in a programming language for
| years or even decades, I think the extra complexity (and
| extra difficulty while learning) is an investment that will
| pay off. But I'd be very happy for rust to stay a niche
| language for systems software. C#, Go, Typescript and Swift
| seem like great choices for making webpages and apps.
| spoiler wrote:
| I think the barrier to entry with Rust is lower than C++. Like
| was way lower... And I've been writing C++ for way long than
| Rust, so I'm probably a bit biased
| josephg wrote:
| > To me it feels like rust is barely readable sometimes. When I
| read some rust cost, I am often incapable to guess what it
| does, so it does not feel intuitive.
|
| I feel torn with this sentiment.
|
| On one hand, I totally agree. Rust's "foreign" ideas (borrowck,
| lifetimes, match expressions, traits, etc) make it harder to
| learn because there's a bunch of new concepts that nobody has
| really worked with before. Some of this stuff - lifetimes and
| borrows especially - really demand a lot of imagination on
| behalf of the programmer to be able to understand what's
| actually going on. The amount of thinking I do per shipped line
| of code seems higher for rust than it does for languages like
| Go, Typescript and C#. And sometimes C.
|
| On the other hand, I learned C about 30 years ago. Not only
| have I forgotten how hard it was to learn, but I had the brain
| of a teenager at the time. And now I'm in my (early) 40s. I'm
| scared that some of the struggle I went through learning rust
| came because my brain is old now, and I've forgotten what its
| like to be out of my depth with a programming language.
| Learning rust requires shaking up some old neurons. And that's
| really good for us, but it sucks.
|
| In reality, I think its a bit of both. I've been using rust a
| lot for about 3-4 years now. Its gotten way easier. But I still
| prototype a fair bit of algorithmic code in typescript first
| because I find TS makes it easier to iterate. That implies rust
| is actually more complex. But, some people pick rust as their
| first language and it seems to work out fine? I'm not sure.
|
| > I don't think the borrow checker forced rust to be such a
| complicated language.
|
| Which parts of rust seem complicated? I've found a lot of the
| things I struggled with at first got a lot easier with
| familiarity. I love traits and match expressions. I love rust's
| implementation of generics. I love most things about cargo and
| the module system. But also, some parts of rust annoy me a lot
| more now, a few years in.
|
| I disagree with your comment. I think the main source of
| complexity in rust comes from lifetimes - which are required by
| the borrow checker. For example, its not obvious when you need
| to put lifetimes in explicitly and when you can elide them.
| When does the borrow checker understand my code? (Eg, can you
| mutably borrow two different elements in an array at the same
| time?). I also still don't really understand Higher-Rank Trait
| Bounds.
|
| I also still find Pin really confusing. In general I think
| async and Futures in rust have some big design flaws. It also
| really bothers me that there's a class of data types that the
| compiler can generate and use, which are impossible to name in
| the language. And some of the rules around derive and traits
| are annoying and silly. Eg derive(Clone) on a generic struct
| adds the constraint T: Clone, which is straight out wrong. And
| rust needs a better answer to the orphan rule.
|
| But in general, if you take out the borrow checker, I find rust
| to be simpler and easier to read than most C++. There's no
| headers. No exceptions. No wild template nonsense. And there's
| generally way less weird magic going on. Eg, Foo(bar); could
| mean about 8 different things in C++. Rust isn't like that.
| Rust is simple enough you can just read the standard library,
| even as a beginner, and its great. C++'s STL is a disaster to
| read.
|
| Rust is definitely more complex than C. But you do get some
| lovely features for that extra cognitive overhead. Whether or
| not thats worth it is up to you. In general - and I've been
| saying this for years - I feel like the language I really want
| is rust 2. I can't wait for someone to take rust's best ideas
| and refine them into a simpler language.
| masklinn wrote:
| > To me it feels like rust is barely readable sometimes. [...]
| C++ have a low barrier of entry and any beginner can write
| code.
|
| Here's rust code: fn main() {
| println!("Hello, world"); }
|
| Here is the equivalent C++ for the vast majority of its life
| (any time before C++23, has MS even shipped C++23 support
| yet?): #include <iostream> int
| main() { std::cout << "Hello World!" << std::endl;
| return 0; }
|
| C++ initialisation alone is a more complex topic than pretty
| much any facet of Rust. And it's not hard to find C++ which is
| utterly inscrutable.
| andrewshadura wrote:
| I don't have a slightest idea why would anyone want this. Borrow
| checking is one of the greatest benefits of Rust.
| Someone1234 wrote:
| It is funny.
| ViewTrick1002 wrote:
| For everyone unaware, this repo is a meme:
|
| https://www.reddit.com/r/rust/comments/1q0kvn1/corroded_upda...
|
| As a follow on to the corroded meme crate:
|
| https://github.com/buyukakyuz/corroded
|
| > _What Is This_
|
| > The rust compiler thinks it knows better than you. It won't let
| you have two pointers to the same thing. It treats you like a
| mass of incompetence that can't be trusted with a pointer.
|
| > We fix that.
| amluto wrote:
| It does seem like satire. The very first example is:
| fn main() { let a = String::from("hello");
| let b = a; println!("{a}"); // Works! Prints:
| hello }
|
| This is not "I have correct code but Rust can't tell it's
| correct." This is "wow, this code is intentionally outrageously
| wrong, obviously dereferences a pointer that is invalid, and
| happens to work anyway."
| 1718627440 wrote:
| > this code is intentionally outrageously wrong
|
| Can you explain why? Why can't both a and b point at the same
| string object? Does `let b = a;` do something like a
| destructive move?
| gpm wrote:
| I'm not 100% sure the semantics here are nailed down - but
| I think there's no guarantee that `a` continues to _exist_
| after assignment to `b`. The value in it has been moved out
| of it after all... The memory which was used for the
| variable `a` can probably be re-used for something else,
| e.g. for some inlined variable used by `println!`...
|
| In normal rust `let a = b` where the variable is of a non-
| Copy type (including String) is "destructive" in the sense
| that you can no longer use b.
|
| The question about semantics in normal rust turns to "so if
| I have a raw-pointer to a hanging around and use unsafe
| code to copy the value out of it what do I get" and I'm not
| 100% sure... but I think the answer is probably it's a use
| after free and you get undefined behavior. The rust--
| version is basically just this except you don't have to
| explicitly make that raw pointer to read the old memory.
| tredre3 wrote:
| The rust way isn't intuitive if you're coming from C, but b
| = a does indeed transfer the ownership to b and a is now
| invalid/unusable. You would need to make a mutable
| reference if you want two variables that point to the same
| object. error[E0382]: borrow of moved
| value: `a` --> main.rs:4:16 | 2
| | let a = String::from("hello"); | -
| move occurs because `a` has type `String`, which does not
| implement the `Copy` trait 3 | let b = a;
| | - value moved here 4 |
| println!("{a}"); // Works! Prints: hello |
| ^ value borrowed here after move | =
| note: this error originates in the macro
| `$crate::format_args_nl` which comes from the expansion of
| the macro `println` (in Nightly builds, run with -Z macro-
| backtrace for more info) help: consider cloning the
| value if the performance cost is acceptable |
| 3 | let b = a.clone(); |
| ++++++++
| aw1621107 wrote:
| > Does `let b = a;` do something like a destructive move?
|
| Yes. Semantically, Rust performs destructive moves by
| default, and as a result using `a` after `let b = a;` would
| normally result in a hard error [0].
|
| The way destructive moves are (currently?) actually
| implemented, however, is as a shallow memcpy of the value
| in question coupled with compiler checks that the moved-
| from thing isn't used. As a result, if you disable the
| compiler check simple uses of the moved-from value
| immediately after the move could still work since the
| compiler doesn't take explicit steps to modify the moved-
| from value immediately after a move.
|
| [0]: https://rust.godbolt.org/z/Wdr6G1GsK
| kace91 wrote:
| I'm not picturing how it works.
|
| In rust you don't have a garbage collector and you don't manually
| deallocate - if the compiler is not certain of who drops memory
| and when, what happens with those ambiguous drops ?
|
| In other words, are the silenced errors guaranteed to be memory
| leaks/use after frees?
| eru wrote:
| I don't think so, I don't think Rust's borrow checker is free
| of false negatives.
| gliptic wrote:
| The borrow checker doesn't decide when things are dropped. It
| only checks reference uses and doesn't generate any code. This
| will work exactly the same as long as your program doesn't
| violate any borrowing rules.
| kace91 wrote:
| No, I get that from an architectural perspective they are
| separate processes. The point is, unlike in other languages,
| the compiler is developed assuming the input has been borrow
| checked, right? So it is surprising to me that it doesn't
| blow up somewhere when that invariant doesn't hold.
| masklinn wrote:
| > So it is surprising to me that it doesn't blow up
| somewhere when that invariant doesn't hold.
|
| The final program may be broken in various manners because
| you don't respect the language's prescribed semantics, in
| about the same way they do in C and C++. From the
| compiler's perspective the borrow checker validates that
| rules it assumes are upheld are actually upheld.
|
| mrustc already compiles rust code without having a borrow
| checker (well IIRC recent-ish versions of mrustc have some
| borrow checking bits, but for the most part it still
| assumes that somebody else has done all the borrow
| checking).
| pornel wrote:
| The compiler has deep assumptions about exclusive ownership
| and moves, which affects destructors and deallocation of
| objects.
|
| It doesn't actually depend on the borrow checker. All
| lifetime labels are discarded after being checked. Code
| generation has no idea about borrow checking. Once the code
| is checked, it is compiled just like C or C++ would, just
| assuming the code is valid and doesn't use dangling
| pointers.
|
| Borrow checker doesn't affect program behavior. It either
| stops compilation or does nothing at all. It's like an
| external static analysis tool.
| andrewaylett wrote:
| In a correct program, the borrow checker has no effect.
|
| Languages like C compile code with the understanding that
| if the compiler can't prove the code is incorrect, it'll
| assume it's correct. Rust compiles with the expectation
| that unless the compiler can prove the code correct
| (according to the language rules), it won't compile it. In
| C, all programs that only perform defined behaviour are
| valid, but many programs which exhibit undefined behaviour
| are also valid. In safe Rust, all programs which exhibit
| undefined behaviour are invalid. But as a trade-off, many
| programs which would actually execute perfectly well are
| also considered invalid.
|
| In both cases, once you get past the layers that check
| stuff, you may normally assume that whatever you have has
| already been shown to be OK and you probably don't have
| enough information to re-check while compiling. It might
| blow up at runtime, it might not.
| MangoToupe wrote:
| Rust's concept of lifetime and scopes exists independently of
| the borrow checker
| juliangoldsmith wrote:
| The silenced errors aren't guaranteed to be memory leaks or use
| after frees. There are some situations where memory is being
| handled properly, but the borrow checker isn't able to prove
| it.
|
| One example might be a tree-like struct where a parent and
| child have references to each other. Even if everything is
| cleaned up properly, the borrow checker has no way to know that
| when the struct is created. Solving it requires unsafe at some
| point, usually through something like RefCell.
| antonvs wrote:
| > In other words, are the silenced errors guaranteed to be
| memory leaks/use after frees?
|
| No, not at all. The examples at the beginning of the article
| show this - they'll execute correctly. The borrow checker is
| quite conservative, and rules out all sorts of code that won't
| (normally!) cause runtime errors.
|
| It's fairly easy to see this if you think about the core of
| Rust's ownership model: every value in Rust has a single owner.
| The compiler enforces that for any value, there's either one
| mutable reference or any number of immutable references to it
| at a time.
|
| This model has the advantage of being simple, easy to reason
| about, and ruling out large classes of errors. But like most
| static checks, including e.g. traditional type checks, it also
| rules out a great deal of otherwise valid code.
|
| It's easy to think of examples in which you have multiple
| mutable references to a value that won't cause errors. Aside
| from trivial examples like in the article, in C-like languages
| you can have many concurrent mutable references to the same
| mutable value. You can safely (with some caveats) manage access
| to it via locks, protocols, documentation, or just being
| careful. Rust with the borrow checker simply doesn't allow
| multiple concurrent mutable references to the same value to
| exist. Rust without the borrow checker, as in the article,
| would allow this.
| gpm wrote:
| I'm pretty sure that every example except example-3 in the
| readme intentionally invokes undefined behavior - if that helps
| you picture how it works ;)
| tmtvl wrote:
| Amazing, this is like the bizarro version of what I'd want. Like
| someone said 'hey, there's this kinda crappy language with a
| really cool feature, let's _not_ make a great language with that
| feature, but instead take the crappy language and remove the cool
| feature which is the only thing keeping it from being trash '.
| Okay, sure, tagged unions, closures, and hygienic macros are
| nice; but there are plenty of other languages with the first two
| and when your syntax is atrocious even the most hygienic macro is
| going to look like something that crawled out of the sewer at
| R'lyeh.
| p0w3n3d wrote:
| There are easier ways of making segfault than writing a custom
| compiler.
| NooneAtAll3 wrote:
| I'd prefer the opposite - borrow checker, but remove the useless
| "fn" and "let" keywords
| reverseblade2 wrote:
| Should be named in rust we don't trust
| 0xMohan wrote:
| I'm assuming it's a meme project. In case it isn't, what's the
| point? Just trying to understand.
|
| Isn't rust's one of the main selling point is the barrow checker
| right?
|
| Also how's the memory is handled? I know it'll drop every thing
| once it's out of scope but it seems you can make copies as much
| as you want. Looking at the loop example, I feel like this
| introduces memory leaks & undefined behavior.
| joelthelion wrote:
| I would actually enjoy that for certain small projects. Rust
| without the borrow checker is a very elegant language. The borrow
| checker is great, of course, but it can be a pain to deal with.
| So, for small projects it would be nice to be able to disable it.
| estebank wrote:
| Instead of disabling the borrow checker what should be possible
| is to promote borrows to Rc/Arc as needed. I would want to
| restrict this mode to one where it can only work locally, never
| publishable to crates.io. It would be particularly useful when
| running tests, then instead of a compile error you can also get
| a runtime error with better information about the cases the
| borrow checker was actually encountering.
| corrode2711 wrote:
| I'm the author of this repo. I see some really angry comments,
| some of them even personal. Obviously I didn't think that just by
| tinkering with a compiler, I'd get personally attacked, but
| anyway, fair enough.
|
| For those of you confused: yes, this started as a satirical
| project with the corroded lib. Then I thought "why not just
| remove the borrow checker?" without any real motivation. Then I
| just went ahead and did it. To my surprise, it was really simple
| and easy. I thought it would be heavily tangled into the rustc
| compiler, but once I figured out where the error emitter is, it
| was pretty straightforward.
|
| I'm not sure about my long-term goals, but besides the joke, I
| genuinely think for debugging and prototyping purposes, I'd like
| the borrow checker to shut up. I'm the kind of guy that prints
| everything while debugging and prototyping. Maybe you're using a
| debugger, okay, but I don't. I don't like debuggers. It's just
| more convenient for me. So what constantly happens is I run into
| issues like: does this implement Debug? Can I print this after it
| moved? The borrow checker won't let me access this because of
| some other borrow. Stuff like that.
|
| Another point is, as you guys are well aware, the borrow checker
| will reject some valid programs in order to never pass any
| invalid program. What if I'm sure about what I'm doing and I
| don't want that check to run?
|
| In the repo there's a doubly linked list example. Without the
| borrow checker it's fairly simple and easy to implement. With it,
| you know how complicated and ugly it gets.
|
| Anyway, have a good new year, and don't get angry over compilers,
| you know.
| whatshisface wrote:
| I think there is probably a way to do what you're doing with
| unsafe. You could write a library that copies handles and can
| dump potentially freed memory afterwards.
| g-mork wrote:
| Some kind of cargo plugin that transforms all references in
| the project into pointers and casts prior to feeding to rustc
| would probably be the best practice and highly maintainable
| route I'd go. like "cargo expand" but with a fancy catchier
| name that encourages new users to rely on it. "cargo autofix"
| might work
| jvanderbot wrote:
| There's definitely a way to do it without unsafe! It just
| isn't as simple as dropping one println out so.... Lets alter
| the compiler?
|
| I gotta applaud that level of my-way-or-the-highway
| CodeMage wrote:
| > Then I thought "why not just remove the borrow checker?"
| without any real motivation.
|
| Reminds me of a chemistry kit I had as a kid. None of this
| tame, safe stuff you can buy these days. Mine was a gift from
| my dad and I never thought of asking him where he dug it up,
| but it had stuff like pure sulfuric acid in it.
|
| One day, when I was done with all of the experiments I had
| planned to do, I decided to mix a few things and heat them up,
| just for fun, without any real motivation other than "let's see
| what happens".
|
| Let's just say I was lucky we only had to replace some of the
| clothes my mom had left out for me to put away. ;)
|
| > Another point is, as you guys are well aware, the borrow
| checker will reject some valid programs in order to never pass
| any invalid program. What if I'm sure about what I'm doing and
| I don't want that check to run?
|
| Then you do it using the "unsafe" keyword, and you think long
| and hard about how to design and structure the code so that the
| unsafe code is small in scope, surface, and blast radius.
|
| That's precisely what unsafe code is for: to get around the
| borrow checker and assert you know what you're doing. Of
| course, if you're wrong, that means your program will blow up,
| but at least you know that the culprit is hiding in one of
| those unsafe areas, rather than literally anywhere in the whole
| codebase.
|
| Alternately, you can switch to a language with a different
| ethos.
|
| The ethos of Rust is caring for memory safety so much that you
| willingly limit yourself in terms of what kind of code you
| write and you only step out of those limits reluctantly and
| with great care. That's something that resonates with a lot of
| people and Rust has been built on top of that for years.
|
| If you suddenly take the product of those years of hard work,
| strip out the foundation it has been built on, and unironically
| offer it as a good idea, a lot of people won't like it and will
| tell you so. Mind, I'm not excusing the personal attacks, I'm
| just explaining the reaction.
| corrode2711 wrote:
| Anything fun is dangerous. Or anything dangerous is fun.
| Something like that.
| npalli wrote:
| You just need to master one package managed in depth and you
| will get what you really want with Modern C++.
| oblio wrote:
| You, sir, might one day belong to the Computing Hall of Fame,
| together with the creators of Brainf*k, Visual Basic, PHP,
| Javascript, ColdFusion, etc. :-p
| indigoabstract wrote:
| My controversial opinion:
|
| If Rust were to "borrow" something from the C/C++ spirit, then
| disabling the borrow checker should be available as a compiler
| option.
|
| As in, you're an adult: if you want it, you can have it, instead
| of "we know better".
| whatshisface wrote:
| If you could disable the borrow checker globally, projects
| would do it, and it would become impossible to compile anything
| with it enabled.
|
| You can already disable it locally: the unsafe keyword is for
| that.
| gpm wrote:
| The unsafe keyword doesn't disable the borrow checker... it
| lets you interact with different pointer types that aren't
| borrow checked, but if you're using the normal reference
| types in rust the same guardrails are still in place.
| klysm wrote:
| Doesn't work - you need the borrow checker guarantees to
| implement downstream compilation steps. You can just turn off
| assumptions
| gpm wrote:
| > you need the borrow checker guarantees to implement
| downstream compilation steps.
|
| You don't technically. The borrow checker doesn't effect the
| semantics of the program (like, for example, type inference
| does) and the rest of the compiler doesn't need to (and in
| fact, doesn't) use its analysis to figure out how to compile
| the code.
|
| The downstream compiler does assume that the code followed
| the rules for accessing references - i.e. didn't violating
| aliasing rules. The borrow checker guarantees this, but it's
| fundamentally a conservative check. It rejects programs it
| can't guarantee are correct, and rice's theorem proves that
| there are always correct programs that it can't guarantee are
| correct.
|
| That said if you just treat rust-references like C-pointers
| you will run into issues. The aliasing rules for rust
| references are stricter. Also not fully agreed upon yet - the
| currently closest to accepted definition is in the "tree
| borrows" paper but it has yet to be adopted as the official
| one by the rust team.
| pornel wrote:
| That's not the spirit Rust wants to have. You can already
| disable borrow checker selectively by using "raw" pointers in
| places where you think you know better, and this is used very
| commonly. Every String in Rust has such raw pointer inside.
|
| It doesn't make much sense to globally relax restrictions of
| Rust's references to be like C/C++ pointers, because the
| reference types imply a set of guarantees: must be non-null
| (affects struct layout), always initialized, and have strict
| shared/immutable vs exclusive access distinction. If you relax
| these guarantees, you'll break existing code that relies on
| having them, and make the `--yolo` flag code incompatible with
| the rest. OTOH if you don't remove them, then you still have
| almost all of borrow checker's restrictions with none of the
| help of upholding them. It'd be like a flag that disables the
| sign bit of signed integers. It just makes an existing type
| mean something else.
| MangoToupe wrote:
| Is rust simple aesthetics to you? Why use rust, or any language
| at all really, at all then? The whole point of formal languages
| is to point a gun at the people who refuse to be adults.
|
| If we can't have this, C itself offers zero benefit over
| assembly.
| indigoabstract wrote:
| I think it's more in the spirit of playfulness, like in
| "don't take yourself too seriously". It's why people want to
| mod Minecraft and Doom for example.
|
| Because it's fun.
|
| I can totally understand why you wouldn't want to do this
| though - the plethora of incompatible lisp dialects come to
| mind. That's why I said it was controversial.
| Wowfunhappy wrote:
| You don't think assembly is more tedious to write than C? I
| don't think that's because of what C does/doesn't "allow" you
| to do.
| yazaddaruvala wrote:
| Of course it is. C does allow named functions and
| variables. C doesn't allow arbitrary jumps.
|
| Those are two reasons why C is less tedious than assembly.
| 1718627440 wrote:
| > C doesn't allow arbitrary jumps.
|
| Have you heard of longjmp?
| shmerl wrote:
| Isn't unsafe just for that? Why does it need a separate compiler?
| idontsee wrote:
| The borrow checker still applies in unsafe { } blocks. What it
| means (iirc) is that you can do pointer/memory stuff that would
| otherwise not be allowed. But you still fully adhere to Rust
| semantics
| andrewaylett wrote:
| Unsafe isn't so unsafe that it disables the borrow checker!
|
| The two main things the compiler allows in an unsafe block but
| not elsewhere are calling other code marked "unsafe" and
| dereferencing raw pointers. The net result is that safe code
| running in a system that's not exhibiting undefined behaviour
| is defined to continue to not exhibit undefined behaviour, but
| the compiler is unable in general to prove that an unsafe block
| _won 't_ trigger undefined behaviour.
|
| You can side-step the borrow checker by using pointers instead
| of references, but using that power to construct an invalid
| reference is undefined behaviour.
| JoelJacobson wrote:
| Rust without async maybe?
| juped wrote:
| This would actually be good though!
| accelbred wrote:
| I've been thinking of writing a language with Rust's ergonomics
| but less of the memory safety stuff. I prefer using no dynamic
| allocations, in which case the only memory safety feature I need
| is leaking references to locals into outer scopes. As for the
| thread safety stuff, most of my stuff is single-threaded.
| giancarlostoro wrote:
| I've been wishing for Rust to become more ergonomic, what
| ergonomics does Rust currently have that other languages lack?
| Null-Set wrote:
| I love how everything is an expression with a value. And
| match expressions are quite nice, especially with the option
| type. I really miss those when working in javascript.
| zeroxfe wrote:
| If Go had rust-style ADTs and pattern matching, and some
| parallel of "?" to short-circuit error handling, I'd be
| thrilled.
| accelbred wrote:
| For me its everything being an expression, macro_rules, dyn,
| automatic conversions (the few that it does have), traits,
| and the ? operator.
| masklinn wrote:
| Affine types / destructive moves, type-level safety signal
| (sync/send), container-type locks.
|
| I really miss these when doing concurrent stuff in other
| languages.
| QuaternionsBhop wrote:
| Fighting the borrow checker is something you do when you're
| learning Rust. After you learn how to design things that way in
| the first place, it's just there to keep you honest.
| tinco wrote:
| To be fair, working on the Rust compiler is also something to
| do when you're learning Rust. I guess this person is killing
| two birds with one stone.
| sakisv wrote:
| As someone who's only did a couple of small toy-projects in rust
| I was never annoyed by the borrow checker. I find it nothing but
| a small mental shift and I kinda like it.
|
| What I _do_ find annoying though and I cannot wrap my head around
| are lifetimes. Every time I think I understand it, I end up
| getting it wrong.
| Maxatar wrote:
| Lifetimes are the input to the borrow checker, so it doesn't
| make much sense to say you have never been bothered by the
| borrow checker but you are bothered by lifetimes.
| ViewTrick1002 wrote:
| Due to lifetime elision you can mostly skip lifetimes if you
| leave a bit of performance on the table.
| zemo wrote:
| way too many people in this thread are taking this project
| seriously
| lamontcg wrote:
| The more I write code in other languages where I think hard about
| ownership ("does this method ultimately grab the object and throw
| a ref onto some long-lived data structure somewhere? Then it owns
| it, so I better clone it") the more robust my code in other
| languages generally gets. Same with mutation. Generally better to
| make a copy of something and then mess with it and throw it away
| than to try to mutate-then-unmutate or something like that, even
| though it might in principle be nanoseconds faster. Eliminate
| loads of spooky-action-a-distance bugs where things are getting
| mutated in one spot and used in another spot, when there should
| have been a copy in there somewhere.
| dmitrygr wrote:
| > Generally better to make a copy of something
|
| > Eliminate loads of spooky-action-a-distance bugs
|
| This line of thinking so sickens me. Many things are not easy
| when done _right_. That is no excuse to avoid understanding how
| to do them right. Sure, making endless copies is easier. But
| this is why machines now need 16GB of ram and four cores to run
| the calculator.
___________________________________________________________________
(page generated 2026-01-01 23:01 UTC)