[HN Gopher] The Algebra of Loans in Rust
___________________________________________________________________
The Algebra of Loans in Rust
Author : g0xA52A2A
Score : 177 points
Date : 2025-12-22 19:25 UTC (4 days ago)
(HTM) web link (nadrieril.github.io)
(TXT) w3m dump (nadrieril.github.io)
| the__alchemist wrote:
| I have what I thought was a broad knowledge base of rust an
| experience in it over many domains, but I haven't heard of most
| of those. Have been getting by with `&`, and `&mut` only from
| those tables!
|
| Incidentally, I think this is one of Rust's best features, and I
| sorely miss it in Python, JS and other languages. They keep me
| guessing whether a function will mutate the parent structure, or
| a local copy in those languages!
|
| Incidentally, I recently posted in another thread here how I just
| discovered the 'named loop/scope feature, and how I thought it
| was great, but took a while to discover. A reply was along the
| effect of "That's not new; it's a common feature". Maybe I don't
| really know rust, but a dialect of it...
| mring33621 wrote:
| I'm just learning Rust but so far, it looks like the author is
| proposing some of these ref types, like &own and &uninit.
|
| I don't know 100% for sure. It's a bit confusing...
| jojomodding wrote:
| The part of the blog post where it says
|
| > What's with all these new reference types? > All of these
| are speculative ideas
|
| makes it pretty clear to me that they are indeed not yet part
| of Rust but instead something people have been thinking about
| adding. The rest of the post discusses how these would work
| if they were implemented.
| whytevuhuni wrote:
| Right. The &pin, &own, and &uninit in the article (or rather
| everything except & and &mut in that table) do not exist in
| Rust.
|
| I have seen &pin being proposed recently [1], first time I'm
| seeing the others.
|
| [1] https://blog.rust-lang.org/2025/11/19/project-goals-
| update-o...
| VorpalWay wrote:
| Own and uninit have been in discussions wrt in place
| construction. The Rust in the Linux kernel project seems to
| be the motivating use case for this that really got the
| effort going recently.
| GardenLetter27 wrote:
| Rust gives you no guarantees that a function won't allocate or
| panic though.
| MaulingMonkey wrote:
| This is something I do wish Rust could better support. A
| `#![no_std]` library crate can at least discourage allocation
| (although it can always `extern crate alloc;` in lib.rs or
| invoke malloc via FFI...)
| maxbond wrote:
| Is the juice worth the squeeze to introduce two new
| function colors? What would you do if you needed to call
| `unreachable!()`?
|
| It's a shame that you can't quite do this with a lint,
| because they can't recurse to check the definitions of
| functions you call. That would seem to me to be ideal,
| maintain it as an application-level discipline so as not to
| complicate the base language, but automate it.
| MaulingMonkey wrote:
| > Is the juice worth the squeeze to introduce two new
| function colors?
|
| Typically no... which is another way of saying
| occasionally yes.
|
| > What would you do if you needed to call
| `unreachable!()`?
|
| Probably one of e.g.: unsafe {
| core::hint::unreachable_unchecked() } loop {}
|
| Which are of course the wrong habits to form! (More
| seriously: in the contexts where such no-panic colors
| become useful, it's because you need to _not_ call
| `unreachable!()`.)
|
| > It's a shame that you can't quite do this with a lint,
| because they can't recurse to check the definitions of
| functions you call. That would seem to me to be ideal,
| maintain it as an application-level discipline so as not
| to complicate the base language, but automate it.
|
| Indeed. You can mark a crate e.g. #![deny(clippy::panic)]
| and isolate that way, but it's not quite the rock solid
| guarantees Rust typically spoils us with.
| VorpalWay wrote:
| > Typically no... which is another way of saying
| occasionally yes.
|
| You might be able to avoid generating panic handling
| landing pads if you know that a function does not call
| panic (transitively). Inlining and LTO often help, but
| there is no guarantee that it will be possible to elide,
| it depends on the whims of the optimiser.
|
| Knowing that panicking doesn't happen can also enable
| other optimisations that wouldn't have been correct if a
| panic were to happen.
|
| All of that is _usually_ very minor, but in a hot loop it
| could matter, and it will help with code size and
| density.
|
| (Note that this is assuming SysV ABI as used by everyone
| except Windows, I have no clue how SEH exceptions on
| Windows work.)
|
| > Indeed. You can mark a crate e.g.
| #![deny(clippy::panic)] and isolate that way, but it's
| not quite the rock solid guarantees Rust typically spoils
| us with.
|
| Also, there are many things in Rust which can panic apart
| from actual calls to panic or unwrap: indexing out of
| bounds, integer overflow (in debug), various std
| functions if misused, ...
| VorpalWay wrote:
| Yes that is annoying, but I don't know of any mainstream
| systems language that does. C and C++ can also have
| allocations anywhere, and C++ have exceptions. And those are
| really the only competitors to Rust for what I do (hard
| realtime embedded).
|
| Zig might be an option in the future, and it does give more
| control over allocations. I don't know what the exception
| story is there, and it isn't memory safe and doesn't have
| RAII so I'm not that interested myself at this point.
|
| I guess Ada could be an option too, but I don't know nearly
| enough about it to say much.
| jibal wrote:
| Zig doesn't have exceptions, it has error unions, so
| basically functions return either a value or an error code
| and the caller is forced by the language to note which was
| returned. And instead of RAII it has defer ... which of
| course can easily be forgotten or mis-scoped, so it's not
| safe.
| gethly wrote:
| For allocation, Zig and Odin. Zig is explicit and Odin is
| implicit.
| prxm wrote:
| > Zig is explicit
|
| i never got this point. whats stopping me from writing a
| function like this in zig? fn
| very_bad_func() !i32 { var GPA =
| std.heap.GeneralPurposeAllocator(.{}){}; var
| gpa = GPA.allocator(); var s = try
| gpa.alloc(i32, 1000); s[0] = 7;
| return s[0]; }
|
| the only thing explicit about zig approach is having
| ready-to-use allocator definitons in the std library. if
| you excluded std library and write your own allocators,
| you could have an even better api in rust compared to zig
| thanks to actual shared behaviour features (traits).
| explicit allocation is a library feature, not a language
| feature.
| gethly wrote:
| the explicit part is that zig forces you to import
| allocator of your choosing whereas odin has allocator
| passed as part of hidden context and you can
| change/access it only if you want to. hence explicit
| behavior vs implicit behavior.
|
| i use neither of those languages, so don't ask me for
| technical details :D
| thegeekpirate wrote:
| You can require allocations in Odin to be explicit using
| `#+vet explicit-allocators`
| FpUser wrote:
| >"Yes that is annoying, but I don't know of any mainstream
| systems language that does. C and C++ can also have
| allocations anywhere, and C++ have exceptions."
|
| C++ has a way to tell to compiler that the function would
| raise no exceptions. Obviously it is not a guarantee that
| at runtime exception will not happen. In that case the
| program would just terminate. So it is up to a programmer
| to turn on some brain activity to decide should they mark
| function as one or not.
| goku12 wrote:
| I doubt that anybody truly knows Rust. And this is aggravated
| by the fact that features keep getting added. But here are two
| simple strategies that I found very effective in keeping us
| ahead of the curve.
|
| 1. Always keep the language reference with you. It's absolutely
| not a replacement for a good introductory textbook. But it's an
| unusually effective resource for anybody who has crossed that
| milestone. It's very effective in spontaneously uncovering new
| language features and in refining your understanding of the
| language semantics.
|
| What we need to do with it is to refer it occasionally for even
| constructs that you're familiar with - for loops, for example.
| I wish that it was available as auto popups in code editors.
|
| 2. Use clippy, the linter. I don't have much to add here. Your
| code will work without it. But for some reason, clippy is an
| impeccable tutor into idiomatic Rust coding. And you get the
| advantage of the fact that it stays in sync with the latest
| language features. So it's yet another way to keep yourself
| automatically updated with the language features.
| VorpalWay wrote:
| I feel like other languages also have the issue of complexity
| and changing over time. I doubt I know all of C++ post C++14
| for example (even though that is my day job). Keeping up with
| all the things they throw into the standard library of Python
| is also near impossible unless you write python every day.
|
| Rust has an unusually short release cycle, but each release
| tends to have fewer things in it. So that is probably about
| the same when it comes to new features per year in Python or
| C++.
|
| But sure, C moves slower (and is smaller to begin with). If
| that is what you want to compare against. But all the
| languages I work with on a daily basis (C++, Python and Rust)
| are sprawling.
|
| I don't have enough experience to speak about other languages
| in depth, but as I understand it Haskell for example has a
| lot of extensions. And the typescript/node ecosystem seems to
| move crazy fast and require a ton of different moving pieces
| to get anything done (especially when it comes to the build
| system with bundlers, minifiers and what not).
| jacquesm wrote:
| Languages should be small, not large. I find that every
| language I've ever used that tries to throw everything and
| the kitchensink at you eventually deteriorates into a mess
| that spills over into the projects based on that language
| in terms of long term instability. You should be able to
| take a 10 year old codebase, compile it and run it.
| Backwards compatibility is an absolute non-negotiable for
| programming languages and if you disagree with that you are
| building toys, not production grade systems.
| aw1621107 wrote:
| > Backwards compatibility is an absolute non-negotiable
| for programming languages
|
| What programming language(s) satisfy this criteria, if
| any?
| GhosT078 wrote:
| Ada does. It has been through 5 editions so far and
| backwards compatibility is always maintained except for
| some small things that are documented and usually easy to
| update.
| aw1621107 wrote:
| I'd normally be inclined to agree that minor things are
| probably good enough, but "absolute non-negotiable" is a
| rather strong wording and i think small things
| technically violate a facial reading, at least.
|
| On the other hand, I did find what I think are the
| relevant docs [0] while looking more into things, so I
| got to learn something!
|
| [0]: https://docs.adacore.com/gnat_rm-
| docs/html/gnat_rm/gnat_rm/c...
| cogman10 wrote:
| > except for some small things that are documented
|
| I can't think of any established language that doesn't
| fit that exact criteria.
|
| The last major language breakage I'm aware of was either
| the .Net 2 to 3 or Python 2 to 3 changes (not sure which
| came first). Otherwise, pretty much every language that
| makes a break will make it in a small fashion that's well
| documented.
| gethly wrote:
| Go, PHP, Ruby, JavaScript ... I'd say majority, actually.
| aw1621107 wrote:
| It's probably borderline due to the opt-in mechanism, but
| Go did make a technically backwards-incompatible change
| to how its for loops work in 1.22 [0].
|
| PHP has had breaking changes [1].
|
| Ruby has had breaking changes [2] (at the very least
| under "Compatibility issues")
|
| Not entirely sure whether this counts, but ECMAScript has
| had breaking changes [3].
|
| [0]: https://go.dev/blog/loopvar-preview
|
| [1]: https://www.php.net/manual/en/migration80.incompatib
| le.php
|
| [2]: https://www.ruby-
| lang.org/en/news/2025/12/25/ruby-4-0-0-rele...
|
| [3]: https://tc39.es/ecma262/2025/#sec-additions-and-
| changes-that...
| gethly wrote:
| There is no such thing as perfection in the real world.
| Close enough is good enough.
| aw1621107 wrote:
| I'd normally agree with you in practice, but since "close
| enough" seems likely to cover most mainstream languages
| in use today I figured "absolute non-negotiable" probably
| was intended to mean a stricter standard.
| kbolino wrote:
| The interesting thing about Go's loopvar change is that
| nobody was able to demonstrate any real-world code that
| it broke (*1), while several examples were found of real-
| world code (often tests) that it _fixed_ (*2).
| Nevertheless, they gated it behind go.mod specifying a go
| version >= 1.22, which I personally think is overly
| conservative.
|
| *1: A great many examples of synthetic code were
| contrived to argue against the change, but none of them
| ever corresponded to Go code anyone would actually write
| organically, and an extensive period of investigation
| turned up nothing
|
| *2: As in, the original behavior of the code was actually
| incorrect, but this wasn't discovered until after the
| loopvar change caused e.g. some tests to fail, prompting
| manual review of the relevant code; as a tangent, this
| raises the question of how often tests just conform to
| the code rather than the other way around
| aw1621107 wrote:
| You certainly won't find me arguing against that change,
| and the conservatism is why I called it borderline. The
| only reason I bring it up is because of the "absolute
| non-negotiable" bit, which I took to probably indicate a
| very exacting standard lest it include most widespread
| languages anyways.
| kbolino wrote:
| Yes, I think it's also a good example of how "absolute"
| backwards compatibility is not necessarily a good thing.
| Not only was the old loopvar behavior probably the
| biggest noob trap in Go (*), it turned out not to be what
| _anyone_ writing Go code in the wild actually wanted,
| even people experienced with the language. Everyone seems
| to have: a) assumed it always worked the way it does now,
| b) wrote code that wasn 't sensitive to it in the first
| place, or c) worked around it but never benefitted from
| it.
|
| *: strongest competitor for "biggest noob trap" IMO is
| using defer in a loop/thinking defer is block scoped
| aw1621107 wrote:
| Strongly agree there. IMO breaking backwards
| compatibility is a tradeoff like any other, and the
| flexibility non-hardline stances give you is handy for
| real-world situations,
| SideburnsOfDoom wrote:
| Yes, most of them.
|
| C# for instance isn't such a "small language", it has
| grown, but code from older versions, that does not use
| the newer features will almost always compile and work as
| before.
|
| breaking changes are for corner cases, e.g. https://githu
| b.com/dotnet/roslyn/blob/main/docs/compilers/CS...
| aw1621107 wrote:
| The thing is that "most of them" seems incongruous with a
| demand for "absolute non-negotiable" backwards
| compatibility. If not for that particular wording I
| probably wouldn't have said anything.
| speed_spread wrote:
| Java rules here. You can take any Java 1.0 (1995)
| codebase and compile it as-is on a recent JDK. Moreover,
| you can also use any ancient compiled Java library and
| link it to modern Java app. Java source and bytecode
| backward compatibility is fantastic.
| aw1621107 wrote:
| Java has had some breaking changes (e.g., [0, 1]), though
| in practice I have to say my experience tends to agree
| and I've been fortunate enough to never run into issues.
|
| [0]: https://stackoverflow.com/q/1654923
|
| [1]: https://news.ycombinator.com/item?id=28542853
| cogman10 wrote:
| * Terms and conditions apply
|
| Java is very good here, but (and not totally it's fault)
| it did expose internal APIs to the userbase which have
| caused a decent amount of heartburn. If your old codebase
| has a route to `sun.misc.unsafe` then you'll have more of
| a headache making an upgrade.
|
| Anyone that's been around for a while and dealt with the
| 8->9 transition has been bit here. 11->17 wasn't without
| a few hiccups. 17->21 and 21->25 have been uneventful.
| VorpalWay wrote:
| Rust does. You have editions to do breaking changes at
| the surface level. But that is per crate (library) and
| you can mix and match crates with different editions
| freely.
|
| Thry do reserve the right to do breaking changes for
| security fixes, soundness fixes and inference changes
| (i.e. you may need to add an explicit type that was
| previously inferred but is now ambiguous). These are
| quite rare and usually quite small.
| aw1621107 wrote:
| I'd normally agree that what you say is good enough in
| practice, but I question whether it meets GP's "absolute
| non-negotiable" standards. That specific wording is the
| reason I asked the question in the first place; it seemed
| to me that there was some standard that apparently wasn't
| being met and I was wondering where exactly the bar was.
| kreetx wrote:
| Haskell's user-facing language gets compiled down to
| Haskell "core" which is what the language actually _can
| do_. So any new language feature has a check in with
| sanity when that first transformation gets written.
| kibwen wrote:
| I'm not sure what this is arguing against here. Anyone
| who follows Rust knows that it's relatively modest when
| it comes to adding new features; most of the "features"
| that get added to Rust are either new stdlib APIs or just
| streamlining existing features so that they're less
| restrictive/easier to use. And Rust has a fantastic
| backwards compatibility story.
| armchairhacker wrote:
| I suspect the problem is that every feature makes it
| possible for an entire class of algorithms to be
| implement much more efficiently and/or clearly with a
| small extension to the language.
|
| Many people encounter these algorithms after many other
| people have written large libraries and codebases. It's
| much easier to slightly extend the language than start
| over or (if possible) implement the algorithm in an ugly
| way that uses existing features. But enough extensions
| (and glue to handle when they overlap) and even a
| language which was initially designed to be simple, is no
| longer.
|
| e.g., Go used to be much simpler. But in particular, lack
| of generics kept coming up as a pain point in many
| projects. Now Go has generics, but arguably isn't simple
| anymore.
| kstrauser wrote:
| Egad, no. This is how you get C++, whose core tenet seems
| to be "someone used this once in 1994 so we can never
| change it".
|
| Even adding a new keyword will break some code out there
| that used that as a variable name or something. Perfect
| backward compatibility means you can never improve
| anything, ever, lest it causes someone a nonzero amount
| of porting effort.
| Someone wrote:
| If you want or have to build a large program, something
| must be large, be it the language, its standard library,
| third party code, or code you write.
|
| I think it's best if it is one of the first two, as that
| makes it easier to add third party code to your code, and
| will require less effort to bring newcomers up to speed
| w.r.t. the code. As an example, take strings. C doesn't
| really have them as a basic type, so third party
| libraries all invent their own, requiring those using
| them to add glue code.
|
| That's why standard libraries and, to a lesser extent,
| languages, tend to grow.
|
| Ideally that's with backwards compatibility, but there's
| a tension between moving fast and not making mistakes, so
| sometimes, errors are made, and APIs 'have' to be
| deprecated or removed.
| rayiner wrote:
| > Languages should be small, not large.
|
| Yes. At the very least, features should carry a lot of
| weight and be orthogonal to other features. When I was
| young I used to pride myself on knowing all the ins and
| outs of modern C++, but over time I realized that needing
| to be a "language lawyer" was a design shortcoming.
|
| All that being said I've never seen the functionality of
| Rust's borrow checker reduced to a simpler set of
| orthogonal features and it's not clear that's even
| possible.
| pjmlp wrote:
| Even C, we are now at C23, and I bet most folks only know
| "my compiler C", and not even all the extensions it offers.
| esafak wrote:
| That's why it's important to get it right early in the
| language. The new stuff may as well not exist.
| gucci-on-fleek wrote:
| I don't know Rust at all, but all your comments
|
| > I doubt that anybody truly knows <language>.
|
| > Always keep the language reference with you.
|
| > Use <tool>, the linter.
|
| seem like they apply to _all_ languages (and I agree that
| they 're great advice!).
| the8472 wrote:
| > All of these are speculative ideas, but at this point they've
| been circulating a bunch so should be pretty robust.
| VorpalWay wrote:
| Many of the things like "&own" are ideas being discussed, they
| don't exist in the language yet. As far as I know only &, &mut
| and raw pointers (mut and const) exist in stable rust at this
| point. The standard library has some additional things like
| NonNull, Rc, etc.
| jibal wrote:
| > I sorely miss it in Python, JS and other languages. They keep
| me guessing whether a function will mutate the parent
| structure, or a local copy in those languages!
|
| Python at least is very clear about this ... everything, lists,
| class instances, dicts, tuples, strings, ints, floats ... are
| all passed by object reference. (Of course it's not relevant
| for tuples and scalars, which are immutable.)
| mrkeen wrote:
| Everything being passed by object reference just means every
| case is equally unclear. answer =
| frobnicate(foo)
|
| Will frobnicate destroy foo or not?
| kstrauser wrote:
| No. It can't. It can only destroy its own reference to foo,
| not the calling scope's reference.
| mrkeen wrote:
| Right, but I don't care about the _reference to foo_
| (that 's a low-level detail that should be confined to
| systems languages, not application languages) I was
| asking about the _foo_.
| kstrauser wrote:
| Right, but that reference is all the function has. It
| can't destroy another scope's reference to the foo, and
| the Python GC won't destroy the foo as long as a
| reference to it exists.
|
| The function could mutate foo to be empty, if foo is
| mutable, but it can't make it not exist.
| mrkeen wrote:
| >> I sorely miss it in Python, JS and other languages.
| They keep me guessing whether a function will mutate the
| parent structure, or a local copy in those languages!
|
| No mention of references!
|
| I don't care about references to foo. I don't care about
| facades to foo. I don't care about decorators of foo. I
| don't care about memory segments of foo.
|
| "Did someone eat my lunch in the work fridge?"
|
| "Well at least you wrote your name in permanent marker on
| your lunchbox, so that should help narrow it down"
| kstrauser wrote:
| Then I don't know what you mean. If you have:
| foo = open('bar.txt') answer = frobnicate(foo)
| print(foo)
|
| then frobnicate may call foo.close(), or it may read
| foo's contents so that you'd have to seek back to the
| beginning before you could read them a second time.
| There's literally nothing you can do in frobnicate that
| can make it such that the 3rd raises a NameError because
| foo no longer exists.
| kibwen wrote:
| _> Incidentally, I recently posted in another thread here how I
| just discovered the 'named loop/scope feature, and how I
| thought it was great, but took a while to discover. A reply was
| along the effect of "That's not new; it's a common feature".
| Maybe I don't really know rust, but a dialect of it..._
|
| I assume I'm the one who taught you this, and for the
| edification of others, you can do labeled break not only in
| Rust, but also C#, Java, and JavaScript. An even more powerful
| version of function-local labels and break/continue/goto is
| available in Go (yes, in Go!), and a yet more powerful version
| is in C and C++.
|
| The point being, the existence of obscure features does not a
| large or complex language make, unless you're willing to call
| Go a large and complex language. By this metric, anyone who's
| never used a goto in Go is using a dialect of Go, which would
| be silly; just because you've never had cause to use a feature
| of a language does not a dialect make.
| morcus wrote:
| Wow, I had no idea JavaScript has labeled break! Thanks for
| the comment.
| nextaccountic wrote:
| Of that table, only & and &mut actually exist, the rest are
| hypothetical syntax
| Sytten wrote:
| Another one that is missing in the article is &raw mut/const
| but it is purely for unsafe usage when you need a pointer to an
| unaligned field of a struct.
| steveklabnik wrote:
| &raw T/&raw mut T aren't pointer types, they're syntax for
| creating *const T/*mut T.
|
| These aren't included in the article because they are not
| borrow checked, but you're right that if someone was trying
| to cover 100% of pointer types in Rust, raw pointers would be
| missing.
| gpm wrote:
| If we start creating more `&... T` ptr types I wonder if a
| future edition changes `*const T` to `&raw T` for
| consistency...
| kibwen wrote:
| I'm hoping that languages move away from the sigil-ified
| legacy of C treating pointers as special syntax and just
| start calling these `Ref<T>`, `PtrConst<T>`, etc.
| steveklabnik wrote:
| Ehhh it's already consistent: ones with & borrow, ones
| without do not.
| sesm wrote:
| TypeScript has `Readonly<T>` for this purpose.
| FpUser wrote:
| >"...and other languages"
|
| Many "other languages", particularly ones that compile to
| native code in traditional way have fairly explicit ways of
| specifying how said parameters to be treated
| amluto wrote:
| Some things I occasionally contemplate: (not that I've ever tried
| to work any of these out anywhere near completely)
|
| 1. Why isn't there a variant of &mut that doesn't allow swapping
| the value? I feel like it ought to be possible to lend out
| permission to mutate some object but not to replace it. Pinning
| the object works, but that's rather extreme.
|
| 2. Would it be safe to lend the reference type above to a pinned
| object? After all, if a function promises to return with the
| passed-in parameter intact in its original location and not to
| swap it with a different value/place, then its address must stay
| intact.
|
| 3. Why is pinning a weird sticky property of a reference?
| Shouldn't non-movability of an object be a property of the
| object's type? Is it just a historical artifact that it works the
| way it does or is this behavior actually desirable?
|
| 4. Wouldn't it be cool if there was a reference type that gave no
| permissions at all but still guaranteed that the referred-to
| object would continue to exist? It might make more sense to use
| with RefCell-like objects than plain &. This new reference type
| could exist concurrently with &mut.
| yuriks wrote:
| For 1, I think it's hard to make a distinction between swapping
| an object, vs. swapping/mutating all of its fields such that it
| becomes equivalent to a different object.
|
| For 3, some objects only need to be pinned under certain
| circumstances, e.g. futures only need to be pinned after
| they're polled for the first time, but not before. So it's
| convenient to separate the pinnability property to allow them
| to be moved freely beforehand.
|
| I don't quite understand the usecase you have in mind for 4.
| amluto wrote:
| > For 1, I think it's hard to make a distinction between
| swapping an object, vs. swapping/mutating all of its fields
| such that it becomes equivalent to a different object.
|
| Privacy. If an object has fields I can't access, but I have
| an &mut reference, I can indirectly modify them by swapping
| the object.
|
| More generally, there are a handful of special-seeming things
| one can do to an object: dropping it, swapping it, forgetting
| it, and leaking it. Rust does not offer especially strong
| controls for these except for pinned objects, and even then
| it feels like the controls are mostly a side effect of
| pinning.
|
| > For 3, some objects only need to be pinned under certain
| circumstances, e.g. futures only need to be pinned after
| they're polled for the first time, but not before.
|
| Is this actually useful in practice? (This is a genuine
| question, not a rhetorical question. But maybe let's pretend
| that Rust had the cool ability to farm out initialization if
| uninitialized objects described in the OP: allowing access
| before pinning sounds a bit like allowing references to
| uninitialized data before initializing it.)
|
| For #4, I'm not sure I have a real use case. Maybe I'll try
| contemplating a bit more. Most I think that shared ^
| exclusive is a neat concept but that maybe there's room to
| extend it a little bit, and there isn't any fundamental
| reason that a holder of an &mut reference needs to ensure
| that no one else can even identify the object while the &mut
| reference is live.
| yuriks wrote:
| > Is this actually useful in practice?
|
| It's required to do any intialization, particularly for
| compound futures (e.g. a "join" or "select" type of
| combinator), since you need to be able to move the future
| from where it's created to where it's eventually
| used/polled. I assume some of those cases could be subsumed
| by &uninit if that existed yeah.
| conradludgate wrote:
| Common wisdom is that pinning is a property of the place, not
| the reference or the type.
|
| A type that might require stable pointers, like async{}, might
| want to be movable prior to use, so you don't want the type to
| require the value be pinned immediately. Or if you do, you need
| a construction like pinned-init that offers `&pin out T` - a
| pinned place that can be written to on initialisation of the
| type.
| kibwen wrote:
| _> Why isn't there a variant of &mut that doesn't allow
| swapping the value?_
|
| This is a very insightful observation, and Niko Matsakis
| (leading influence of Rust's borrow checker) would likely agree
| with you that this is an instance where Rust's default
| borrowing rules are probably too permissive, in the sense that
| being more restrictive by default regarding the "swappability"
| of &mut could lead to Rust being able to provide more
| interesting static guarantees. See his blog post here:
| https://smallcultfollowing.com/babysteps/blog/2024/09/26/ove...
|
| _> Why is pinning a weird sticky property of a reference?
| Shouldn't non-movability of an object be a property of the
| object's type?_
|
| See this blog post from withoutboats:
| https://without.boats/blog/pinned-places/ for arguments as to
| why pinning is properly modeled as a property of a place rather
| than a type (particularly the section "Comparison to immovable
| types"), as well as this post from Niko that ties this point in
| with the above point regarding swappability:
| https://smallcultfollowing.com/babysteps/blog/2024/10/14/ove...
| oconnor663 wrote:
| Yes I'm especially interested in what OP thinks about the
| overlap (or not?) between the ideas in this post and the
| ideas in this part of boats' post:
|
| > One could imagine an alternative design in which instead of
| places being unpinned by default and opting into pinning,
| places are pinned (or perhaps "immovable") by default, and
| have to opt into supporting the ability to move out of them.
| This would make it so that by default places have the least
| power (can only access via shared reference) and they gain a
| monotonically increasing set of powers (can assign to them,
| can move out of them).
|
| > In addition to places having to opt into moving, there
| would be three reference types instead of two: immutable,
| mutable, and movable references.
| asciii wrote:
| I was thinking this is some accounting primer in Rust...dang,
| still good stuff to know.
| meisel wrote:
| What does this sort of language complexity mean for future
| changes in Rust? In C++, its existing complexity makes new
| changes so much more difficult. Is Rust reaching a similar place?
| kibwen wrote:
| Can you be more specific? What language complexity are you
| referring to? Plenty of things in this post are hypothetical,
| not actual features being surfaced by the language.
| trevortheblack wrote:
| Am i mistaken or is there an error in the writing?
|
| > For example, if I have a &own T I can reborrow it into a &mut T
| but not a &pin own T.
|
| From the table can't you do both? Maybe they mean "not a &pin mut
| T" ?
___________________________________________________________________
(page generated 2025-12-26 23:01 UTC)