The article explains most of this, but the key takeaway for beginners once this lands is: With `become` you can write tail calls in Rust and it will promise they either work or don't compile, you can't have the case (which exists in several languages) where you thought you'd written a tail call but you hadn't (or maybe you had but you switched to a different compiler or made a seemingly inconsequential change to the code) and now the stack has overflowed.
Rust has been really good at providing ergonomic support for features we're too used to seeing provided as "Experts only" features with correspondingly poor UX.
"Either it works or doesn't compile" compared to "oops it silently degraded to the less performant thing because an invariant stopped being true" is remarkably similar to how I tend to describe the benefit of having move semantics by default with opt-in copies in Rust compared to in C++ where you need to set up things right and might still accidentally have it copy if you mess it up.
No, it is used for loops within functions as well. But it’s not fully generalized like in Scheme. You can’t have mutually recursive functions using tail recursion via “recur,” for instance. There is another Clojure technique for that (“trampoline”). Clojure runs on the JVM and is limited by the JVM’s original omission of TCO. When I started using Clojure, I was concerned about these limitations, but in practice I haven’t found them to be a problem. Most of the time, I just need a loop and “recur” works fine. I rarely use “trampoline” (just for state machines).
I like this change. I was wondering if I would've preferred to have something on the function signature (eg `tcc_fn foo() ...` as in Tail Call Constrained fn) and when encountering that the rust compiler would make checks about whether the body of the function is tail-callable.
My fear is that adding yet another keyword it might get lost in the sea of keywords that a Rust developer needs to remember. And if recursion is not something you do often you might not reach for it when actually needed.
Having this signal in the function signature means that people would be exposed to it just by reading the documentation and eventually will learn it exists and (hopefully) how to wield it.
The property we care about isn't a property of functions but of callers, so marking a function doesn't help.
`become blah(foo, bar)` is the same thing as `blah(foo, bar)` except that we, the caller are promising that we have nothing further to do and so when blah returns it can return to our caller.
If somebody else calls blah they don't want that behaviour, they might have lots more to do and if they were skipped over that's a disaster.
In some languages it's very obvious when you're going to get TCO anyway, but Rust has what C++ calls RAII, when a function ends all the local variables get destroyed and this may be non-trivial work. Presumably destroying a local i32 is trivial & so is a [u8; 32] but destroying a local String isn't, let alone a HashMap and who knows how complicated it is to destroy a File or a DBQuery or a Foo...
So in a sense "all" become does is try to bring that destruction sooner a little, so it happens before the call, leaving nothing to do afterwards. We weren't using that String any more anyway, lets just destroy it first, and the HashMap? Sure, and oh... no, actually if we destroy that Foo before calling blah which needs the Foo that messes things up... Rust's borrowck comes in clutch here to help us avoid a terrible mistake, our code was nonsense, it doesn't build.
Given that it's not really that uncommon to see something like `pub(crate) async fn foo() ...`, the concern of function signatures starting to get unwieldy feels a lot more concrete than hypotheticals about a "sea of keywords". From looking at the list of keywords in the language currently (listed here: https://doc.rust-lang.org/std/#keywords), I don't really see a whole lot that I think the average Rust programmer would say is a burden to have to remember. At most, `union` and `unsafe` are probably ones that most Rust programmers are not going to need to use directly, and `SelfTy` might look a bit confusing at first due to the fact that the keyword itself is spelled `Self` (and presumably listed in that way to make it easier to differentiate from the `self` entry in the documentation), but even including those I'd argue that probably over half aren't specific to Rust.
As for being in the documentation, I'd argue that might even be an explicit non-goal; it's not clear to me why that should be something considered part of the API. If someone updates their tail recursive function to manually loop instead (or vice-versa), it doesn't seem like that should necessitate the documentation being updated.
I'd actually say that for people learning Rust after something like C or C++ in particular the rare cases where a keyword means something else are the most confusing. In particular `const` in Rust means constant whereas in several languages it means an immutable variable.
const NINE: i32 = // Some arbitrary *constant* expression;
In K&R C this qualifier didn't exist so there's no confusion, but C89, all versions of C++ and several other languages inspired by them use "const" to mean an immutable variable.
That's a fair point, and maybe even a case that there should be more keywords rather than fewer.
Relatedly, I still sometimes get tripped up by the nuances of using `const` versus `static` for top-level constants. Most of the time the difference is entirely opaque to the programmer (because it's not obvious when most things are getting inlined or being referenced from a single place in memory), but it's possible to run into cases where one works and the other won't (e.g. trying to be clever with `OnceCell` rather than `OnceLock`).
It might help to think about whether you want an actual singular concrete thing, which means you need static or whether you just want to talk about the idea and so it doesn't matter whether at runtime this exists many places or nowhere at all, which is a const.
Statics can be mutated - though not safely - because they are a single concrete thing so they can be changed, whereas it can't mean anything to mutate a constant, hence the word "constant".
For larger objects you might want a single concrete thing even though it might intuitively not seem important because it impacts performance. For example if we keep talking about FACTOR[n] where FACTOR is an array of a million numbers (maybe computed by scientist colleagues for your application) and n is a variable, if FACTOR is const Rust is going to just put a copy of that enormous array everywhere it needed to do this indexing operation, which gets out of hand really fast, whereas if we use static we get a single concrete thing, named FACTOR and everywhere in the program will use that one single million number array, much tidier and less likely to result in say, running out of RAM on a small computer.
I was wondering how they solved the `drop` problem (the fact that `return foo;` is not the last code executed in most functions, because Rust values are all implicitly dropped at the end of scope), and it seems that they cut the Gordian knot so that values are all implicitly dropped before `become` instead. Hope that works out - probably why it's still nightly for now.
Nor in the physical world either. Crumbling planes, trains and automobile infrastructure. Collapsed bridges, airports that don't function properly etc.
As someone who has experienced a Migration to SAP, no it is quite hard to say it is good. Doesn't work on mobile (unless you toggle on "desktop" mode, at which point if kinda works), is slower than the preceding PHP solution and generally functions like a POS. Other SAP implementations did not seem to behave much better.
They might have some great software _somewhere_ but I have yet to see it.
SAP software is the bane of most people, who have to use it, except for expensive consultants, who make bank preying on hapless clueless companies opting to use SAP software.
SAP is very good at what it is trying to do, which is to define, standardize, automate and run a business process, and it is equipped with a large library of premade processes so you don't have to reinvent the wheel.
It does not have good UX because good UX was never the objective.
We had people formerly saying that in our org and going to a _decade_ of several failed ERPs.
Now we run SAP.
Still people are unsatisfied with SAP. Not even recognising that the failures are mostly self instricted policies.
The organisation worked somehow before having an ERP, because people ignored the given organisation and improvised. That's close to impossible if you use digital processes from end to end.
And yet, the ones with the poor organisational skills blame software.
There’s something to be said for human readable addresses. I’m a little nostalgic of how the .hack world was envisioned, where servers had address names like Hidden Forbidden Holy Ground.
If roughly 10 million words exist, then allowing any three words in order creates a space for 10^21 addresses… five words and you’re close to ipv6 address space, six words and there’s more combinations than ipv6 addresses.
You can set your ULA to something like "fddd:192:168::/48" and then on your vlan you prefix hint, say, "66". Now, any device on that vlan will be addressable by "fddd:192:168:66::$host". For example, your gateway ('router') for that vlan would be "fddd:192:168:66::1".
If you want to be really wonky you can script DHCPv6 to statically assign ULA IPv6 leases that match the IPv4, and expire them when the IPv4 lease expires, but like said upthread, addressing hosts via IPv6 is the wrong way to go about it. On your lan, you really want to be doing ".local" / ".lan" / ".home".
> addressing hosts via IPv6 is the wrong way to go about it. On your lan, you really want to be doing ".local" / ".lan" / ".home".
.local is fine as long as all the daemons work correctly, but AFAIK there's no way to have SLAAC and put hosts in "normal" internal DNS, so .lan/.home/.internal are probably out.
> On your lan, you really want to be doing ".local" / ".lan" / ".home".
The "official" is home.arpa according to RFC 8375 [1]:
Users and devices within a home network (hereafter referred to as
"homenet") require devices and services to be identified by names
that are unique within the boundaries of the homenet [RFC7368]. The
naming mechanism needs to function without configuration from the
user. While it may be possible for a name to be delegated by an ISP,
homenets must also function in the absence of such a delegation.
This document reserves the name 'home.arpa.' to serve as the default
name for this purpose, with a scope limited to each individual
homenet.
It may be the most officially-recommended for home use, but .internal is also officially endorsed for "private-use applications" (deciding the semantics of these is left as an exercise to the reader): https://en.wikipedia.org/wiki/.internal
".home" and ".lan" along with a bunch of other historic tlds are on the reserved list and cannot be registered.
Call techy people pathologically lazy but no one is going to switch to typing ".home.arpa" or ".internal". They should have stuck with the original proposal of making ".home" official, instead of sticking ".arpa" behind it. That immediately doomed the RFC.
I do it by abusing the static slaac address. I have a set of wierd vms where they are cloned from a reference image, so no fixed config allowed. I should have probably just have used dhcp6 but I started by trying slaac and the static address were stable enough for my purposes so it stuck.
How does that work? I initially assumed you meant you just statically assigned machines to addresses, which I think would work courtesy of collision avoidance (and the massive address space), but I can't see how that would work for VMs. Are you just letting VMs pick an IP at random and then having them never change it, at which point you manually add them to DNS?
Pretty much. A given mac address assigned in the vm config maps directly to a static slaac address(the ones they recommend you not use) and those preknown slaac address are in dns, Like I said, I should probably use dhcp6 but it was a personal experiment in cloning a vm for a sandbox execution environment. and those slacc address were stable enough for that. every time it gets cloned to the same mac address it ended up with the same ip6 address. works for me, don't have to faf around with dhcp6, put it in dns. time for a drink.
But the point is that is the address you would put in dns if you also wanted to use slaac. Most of the time however you will just set a manual address. And this was with obsd, where when slaac is setup you get the slaac address and a temporary address. I don't really know what linux does. Might have to try now.
Clarification for others: with privacy extensions disabled, SLAAC'd IPv6 addresses are deterministically generated based on MAC addresses. There's also an inbetween (IPv6 are stable per network by hashing).
You have to take into account seasonal trends. The summer is always higher, so yes, we’re currently below last summer, but we are above last April 1st, and this summer will be higher than last summer.
You can’t compare fall winter and spring to last July. You have to compare last July to this July, which hasn’t happened yet, but when it does, it will be higher than last July. Today (April) is higher than last April.
The reason for this is that more people are on mobile connections during the summer (kids home from school) so the summer (as well as the Christmas/new year week) are the highest points of the year.
The fact that it’s “flat” since last July, the high season, means it’s actually still increasing.
> Regardless, when you extrapolate that curve, when do you estimate hitting 100%?
Never? But what’s your point? IPv6 is a failure if it only replaces IPv4 for 99% of traffic?
Until the place you're VPNing to happens to use the same RFC1918 network address as your LAN (that is, your LAN is 192.168.10.x and the network on the other side of your work's VPN is also 192.168.10.x). Or either of them use the same RFC1918 network address libvirt is using for its virtual network. Or you want to route between several LANs (for instance, after a company merger) and some of them (but not all) were using the same RFC1918 network addresses.
All of this is avoided by using public addresses for LANs, but address scarcity makes that hard with IPv4 (unless it's a legacy LAN from the 1900s which happens to still use public addresses form the pre-NAT era).
Don't confuse "simple and good" with "flawless" :-)
There are indeed only a few private-reserved IPv4 ranges, and almost everyone prefers to keep things memorable and easy to type; you get a lot of 10.0.0.0/24, 192.168.0.0/24, 192.168.1.0/24 as a result. That, and common household routers tend to default to one of these three /24 subnets. (Hardly anyone seems to remember that 172.16.0.0/12 exists, feel free to use that if it happens to work for you.)
IPv6 does solve this issue in a few major ways, one of which is the greater expectation to rely on globally routable addresses, of which every one of your devices will have at least one such address. There's also fc00::/7 which is fairly equivalent to the IPv4 private ranges, though to avoid conflicts in random VPNs you should generate a random /64 prefix inside of this, otherwise you run the risk of everyone picking fc00::/64 because it's easy to remember/type (I'm guilty of this myself, but the VPNs I've configured just go into a random 172.16.0.0/12 subnet and no v6 assigned. I have the liberty that I currently don't need/use any VPNs that I haven't personally configured, and that may not hold true in the future.)
Huh, I have matter devices working here and IPv6 is off on my router and DHCP. And on home assistant too which does the matter router. Does it use link local or something?
While I concede that powerbanks may satisfy the proximal problem - literally making charging available on demand...
Consider that it does not in any way resolve the distal problem of having a 'portable computing device', which heavily compromises on the 'portable' aspect - by forcing a state of permanent battery anxiety without external life support (i.e. no power source - dead in minutes of intensive work)
The powerbank is a fine workaround to be fair, but as I see it: still a workaround at best. The ability to swap a battery without getting into things like soldering - allows for far more flexible functionality and longevity than a powerbank could.
That is without even mentioning the ultimate problem of parts sustainability and longevity. When you can swap individual components as they degrade, it's possible to use the rest of the machine for far longer than a degraded battery or a failing SSD would allow.
Powerbanks simply feel like treating symptoms, instead of rehabilitating the system itself (obviously still use them for phones and such of course)
Maybe like 0.01% of users ever did that, or did any upgrades to their laptops. Moving to recyclable but integrated components is the right move for the vast majority of people. I’m sure there are some compromised devices for nerds out there that still allow for swapping batteries etc
https://doc.rust-lang.org/std/keyword.become.html
reply