@maegul@lemmy.ml
@maegul@lemmy.ml avatar

maegul

@maegul@lemmy.ml

A little bit of neuroscience and a little bit of computing

This profile is from a federated server and may be incomplete. Browse more on the original instance.

maegul,
@maegul@lemmy.ml avatar

So I’ve been ranting lately (as have others) about how big tech is moving on from the open user-driven internet and aiming to build its own new thing as an AI interface to all the hoovered data (rather than conventional search engines) …

which makes this (and the underlying Bing going down) feel rather eerie.

How far away (in time or probability) is a complete collapse of the big search-engines … as in they just aren’t there any more?

maegul,
@maegul@lemmy.ml avatar

in line with map_enthusiasts: !dataisbeautiful (and also !dataisbeautiful , which is smaller IIRC)

maegul,
@maegul@lemmy.ml avatar

The moment word was that Reddit (and now Stackoverflow) were tightening APIs to then sell our conversations to AI was when the game was given away. And I’m sure there were moments or clues before that.

This was when the “you’re the product if its free” arrangement metastasised into “you’re a data farming serf for a feudal digital overlord whether you pay or not”.

Google search transitioning from Good search engine for the internet -> Bad search engine serving SEO crap and ads -> Just use our AI and forget about the internet is more of the same. That their search engine is dominated by SEO and Ads is part of it … the internet, IE other people’s content isn’t valuable any more, not with any sovereignty or dignity, least of all the kind envisioned in the ideals of the internet.

The goal now is to be the new internet, where you can bet your ass that there will not be any Tim Berners-Lee open sourcing this. Instead, the internet that we all made is now a feudal landscape on which we all technically “live” and in which we all technically produce content, but which is now all owned, governed and consumed by big tech for their own profits.


I recall back around the start of YouTube, which IIRC was the first hype moment for the internet after the dotcom crash, there was talk about what structures would emerge on the internet … whether new structures would be created or whether older economic structures would impose themselves and colonise the space. I wasn’t thinking too hard at the time, but it seemed intuitive to that older structures would at least try very hard to impose themselves.

But I never thought anything like this would happen. That the cloud, search/google, mega platforms and AI would swallow the whole thing up.

maegul, (edited )
@maegul@lemmy.ml avatar

I dunno, my feeling is that even if the hype dies down we’re not going back. Like a real transition has happened just like when Facebook took off.

Humans will still be in the loop through their prompts and various other bits and pieces and platforms (Reddit is still huge) … while we may just adjust to the new standard in the same way that many reported an inability to do deep reading after becoming regular internet users.

maegul,
@maegul@lemmy.ml avatar

Oh yea, it’s basically a vibe now for those who see it, which I was mostly channeling.

maegul,
@maegul@lemmy.ml avatar

Yea but this feels quicker than anyone expected. It’s easy to forget, but alpha Go beating the best in the world was shocking at the time and no one saw it coming. We hadn’t sorted out what to do with big monopoly corps yet, we weren’t ready for a whole new technology.

maegul,
@maegul@lemmy.ml avatar

Great take.

Older/less tech literate people will stay on the big, AI-dominated platforms getting their brains melted by increasingly compelling, individually-tailored AI propaganda

Ooof … great way of putting it … “brain melting AI propaganda” … I can almost see a sci-fi short film premised on this image … with the main scene being when a normal-ish person tries to have a conversation with a brain-melted person and we slowly see from their behaviour and language just how melted they’ve become.

Maybe we’ll see an increase in discord/matrix style chatroom type social media, since it’s easier to curate those and be relatively confident everyone in a particular server is human.

Yep. This is a pretty vital project in the social media space right now that, IMO, isn’t getting enough attention, in part I suspect because a lot of the current movements in alternative social media are driven by millennials and X-gen nostalgic for the internet of 2014 without wanting to make something new. And so the idea of an AI-protected space doesn’t really register in their minds. The problems they’re solving are platform dominance, moderation and lock-in.

Worthwhile, but in all serious about 10 years too late and after the damage has been done (surely our society would be different if social media didn’t go down the path it did from 2010 onward). Now what’s likely at stake is the enshitification or en-slop-ification (slop = unwanted AI generated garbage) of internet content and the obscuring of quality human-made content, especially those from niche interests. Algorithms started this, which alt-social are combating, which is great.

But good community building platforms with strong privacy or “enclosing” and AI/Bot protecting mechanisms are needed now. Unfortunately, all of these clones of big-social platforms (lemmy included) are not optimised for community building and fostering. In fact, I’m not sure I see community hosting as a quality in any social media platforms at the moment apart from discord, which says a lot I think. Lemmy’s private and local only communities (on the roadmap apparently) is a start, but still only a modification of the reddit model.

maegul,
@maegul@lemmy.ml avatar

LOL (I haven’t actually met someone like that, in part because I’m not a USian and generally not subject to that sort of type ATM … but I am morbidly curious TBH.

maegul, (edited )
@maegul@lemmy.ml avatar

Yea, US, can you just fucking not be a petulant child.

Minnesota Congresswoman Ilhan Omar said the court’s allegations are “significant” and the US must support its work as it has done on past occasions, including in the case of Libya.

“The application for arrest warrants is merely the beginning of a judicial process,” she wrote in a statement on Monday.

“The ICC has been a functioning court – it has seen convictions, acquittals, and dismissals, as we would expect from an impartial and non-political judicial body.”

Only clear headed response in the article.

maegul, to mastodon
@maegul@hachyderm.io avatar

UI differences are a big factor in the success/failure of decentralised federation of diverse platforms and content

And this seems a good example: bridged posts onto which has a lower character limit than Mastodon.

So, just like posts on mastodon, you don't get the full content of the post (which ends with an abrupt ellipsis here) and have to take a link to the original platform.

However powerful the underlying protocols, this isn't far from screenshots.

@fediverse

maegul,
@maegul@lemmy.ml avatar

Eh. AP isn’t magic. Platforms can be pretty incompatible because of their differing use or implementation of AP. I feel like at some point there’s a blurry line between a bridge being something different and just an extension of 2 protocols.

maegul,
@maegul@lemmy.ml avatar

Yea a complete protocol to protocol bridge seems far off for sure. But a platform to platform bridge seems to be working fine for the moment (masto-bsky), and that seems a reasonable expectation.

maegul,
@maegul@lemmy.ml avatar

Yea, car congestion isn’t about industrial transport, it’s about personal transport. All of the people commuting to/from work etc in single person occupied tanks.

maegul,
@maegul@lemmy.ml avatar

If I had to explain ownership in rust (based on The Book, Ch 4)

I had a crack at this and found myself writing for a while. I thought I’d pitch at a basic level and try to provide a sort core and essential conceptual basis (something which I think The Book might be lacking a little??)

Dunno if this will be useful or interesting to anyone, but I found it useful to write. If anyone does find any significant errors, please let me know!

General Idea or Purpose

  • Generally, the whole point is to prevent memory mismanagement.
  • IE “undefined behaviour”: whenever memory can be read/written when it is no longer controlled by a variable in the program.
    • Rust leans a little cautious in preventing this. It will raise compilation errors for some code that won’t actually cause undefined. And this is in large part, AFAICT, because its means of detecting how long a variable “lives” can be somewhat course/incomplete (see the Rustonomicon). Thus, rust enforces relatively clean variable management, and simply copying data will probably be worth it at times.

Ownership

  • Variables live in, or are “owned by” a particular scope (or stack frames, eg functions).
  • Data, memory, or “values” are owned by variables, and only one at a time.
  • Variables are stuck in their scopes (they live and die in a single scope and can’t be moved out).
  • Data or memory can be moved from one owning variable to another. In doing so they can also move from one scope to another (eg, by passing a variable into a function).
  • Once a variable has its data/memory moved to another, that variable is dead.
  • If data/memory is not moved away from its variable by the completion of its scope, that data/memory “dies” along with the variable (IE, the memory is deallocated).

<span style="font-style:italic;color:#969896;">// > ON THE HEAP
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// Ownership will be "moved" into this function's scope
</span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">take_ownership_heap</span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">_</span><span style="color:#323232;">: Vec<</span><span style="font-weight:bold;color:#a71d5d;">i32</span><span style="color:#323232;">>) {}
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> a </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">vec![</span><span style="color:#0086b3;">1</span><span style="color:#323232;">, </span><span style="color:#0086b3;">2</span><span style="color:#323232;">, </span><span style="color:#0086b3;">3</span><span style="color:#323232;">];
</span><span style="color:#62a35c;">take_ownership_heap</span><span style="color:#323232;">(a);
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// ERROR
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> b </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> a[</span><span style="color:#0086b3;">0</span><span style="color:#323232;">];
</span><span style="font-style:italic;color:#969896;">// CAN'T DO: value of `a` is borrowed/used after move
</span><span style="font-style:italic;color:#969896;">// `a` is now "dead", it died in `take_ownership_heap()`;
</span>

  • Variables of data on the stack (eg integers) are implicitly copied (as copying basic data types like integers is cheap and unproblematic), so ownership isn’t so much of an issue.
  • Copying (or cloning) data/memory on the heap is not trivial and so must be done explicitly (eg, with my_variable.copy()) and in the case of custom types (eg structs) added to or implemented for that particular type (which isn’t necessarily difficult).

<span style="font-style:italic;color:#969896;">// > ON THE STACK
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// An integer will copied into `_`, and no ownership will be moved
</span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">take_ownership_stack</span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">_</span><span style="color:#323232;">: </span><span style="font-weight:bold;color:#a71d5d;">i32</span><span style="color:#323232;">) {}
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> x </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">11</span><span style="color:#323232;">;
</span><span style="color:#62a35c;">take_ownership_stack</span><span style="color:#323232;">(x);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> y </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> x </span><span style="font-weight:bold;color:#a71d5d;">* </span><span style="color:#0086b3;">10</span><span style="color:#323232;">;
</span><span style="font-style:italic;color:#969896;">// NOT A PROBLEM, as x was copied into take_ownerhsip_stack
</span>

Borrowing (with references)

  • Data can be “borrowed” without taking ownership.
  • This kind of variable is a “reference” (AKA a “non-owning pointer”).
  • As the variable doesn’t “own” the data, the data can “outlive” the reference.
    • Useful for passing a variable’s data into a function without it “dying” in that function.

<span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">borrow_heap</span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">_</span><span style="color:#323232;">: </span><span style="font-weight:bold;color:#a71d5d;">&</span><span style="color:#323232;">Vec<</span><span style="font-weight:bold;color:#a71d5d;">i32</span><span style="color:#323232;">>) {}
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> e </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">vec![</span><span style="color:#0086b3;">1</span><span style="color:#323232;">, </span><span style="color:#0086b3;">2</span><span style="color:#323232;">, </span><span style="color:#0086b3;">3</span><span style="color:#323232;">];
</span><span style="font-style:italic;color:#969896;">// pass in a reference
</span><span style="color:#62a35c;">borrow_heap</span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">&</span><span style="color:#323232;">e);
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> f </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> e[</span><span style="color:#0086b3;">0</span><span style="color:#323232;">];
</span><span style="font-style:italic;color:#969896;">// NOT A PROBLEM, as the data survived `borrow_heap`
</span><span style="font-style:italic;color:#969896;">// because `e` retained ownership.
</span><span style="font-style:italic;color:#969896;">// &e, a reference, only "borrowed" the data
</span>
  • But it also means that the abilities or “permissions” of the reference with respect to the data are limited and more closely managed in order to prevent undefined behaviour.
  • The chief limitation is that two references cannot exist at the same time where one can mutate the data it points to and another can read the same data.
  • Multiple references can exist that only have permission to read the same data, that’s fine.
  • The basic idea is to prevent data from being altered/mutated while something else is reading the same data, as this is a common cause of problems.
  • Commonly expressed as Pointer Safety Principle: data should never be aliased and mutated at the same time.
  • For this reason, shared references are “read only” references, while unique references are mutable references that enable their underlying data to be mutated (AKA, mutable references).
    • A minor confusion that can arise here is between mutable or unique references and reference variables that are mutable. A unique reference is able to mutate the data pointed to. While a mutable variable that is also a reference can have its pointer and the data/memory and points to mutated. These are independent aspects and can be freely combined.
    • Perhaps easily understood by recognising that a reference is just another variable whose data is a pointer or memory address.
  • Additionally, while variables of data on the stack typically don’t run into ownership issues because whenever ownership would be moved the data is implicitly copied, references to such variables can exist and they are subject to the same rules and monitoring by the compiler.

<span style="font-style:italic;color:#969896;">// >>> Can have multiple "shared references"
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> e_ref1 </span><span style="font-weight:bold;color:#a71d5d;">= &</span><span style="color:#323232;">e;
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> e_ref2 </span><span style="font-weight:bold;color:#a71d5d;">= &</span><span style="color:#323232;">e;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> e1 </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> e_ref1[</span><span style="color:#0086b3;">0</span><span style="color:#323232;">];
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> e2 </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> e_ref2[</span><span style="color:#0086b3;">0</span><span style="color:#323232;">];
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// >>> CANNOT have shared and mutable/unique references
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let mut</span><span style="color:#323232;"> j </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">vec![</span><span style="color:#0086b3;">1</span><span style="color:#323232;">, </span><span style="color:#0086b3;">2</span><span style="color:#323232;">, </span><span style="color:#0086b3;">3</span><span style="color:#323232;">];
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// A single mutable or "unique" reference
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> j_mut_ref </span><span style="font-weight:bold;color:#a71d5d;">= &mut</span><span style="color:#323232;"> j;
</span><span style="font-style:italic;color:#969896;">// can mutate the actual vector
</span><span style="color:#323232;">j_mut_ref[</span><span style="color:#0086b3;">0</span><span style="color:#323232;">] </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">11</span><span style="color:#323232;">;
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// ERROR
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> j_ref </span><span style="font-weight:bold;color:#a71d5d;">= &</span><span style="color:#323232;">j;
</span><span style="font-style:italic;color:#969896;">// CANNOT now have another shared/read-only reference while also having a mutable one (j_mut_ref)
</span><span style="font-style:italic;color:#969896;">// mutation actually needs to occur after the shared reference is created
</span><span style="font-style:italic;color:#969896;">// in order for rust to care, otherwise it can recognise that the mutable
</span><span style="font-style:italic;color:#969896;">// reference is no longer used and so doesn't matter any more
</span><span style="color:#323232;">j_mut_ref[</span><span style="color:#0086b3;">1</span><span style="color:#323232;">] </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">22</span><span style="color:#323232;">;
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// same as above but for stack data
</span><span style="font-weight:bold;color:#a71d5d;">let mut</span><span style="color:#323232;"> j_int </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">11</span><span style="color:#323232;">;
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> j_int_mut_ref </span><span style="font-weight:bold;color:#a71d5d;">= &mut</span><span style="color:#323232;"> j_int;
</span><span style="font-style:italic;color:#969896;">// ERROR
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> j_int_ref </span><span style="font-weight:bold;color:#a71d5d;">= &</span><span style="color:#323232;">j_int;
</span><span style="font-style:italic;color:#969896;">// CANNOT assign another reference as mutable reference already exists
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">*</span><span style="color:#323232;">j_int_mut_ref </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">22</span><span style="color:#323232;">;
</span><span style="font-style:italic;color:#969896;">// dereference to mutate here and force rust to think the mutable reference is still "alive"
</span>

Ownership and read/write permissions are altered when references are created

  • The state of a variable’s ownership and read-only or mutable permissions is not really static.
  • Instead, they are altered as variables and references are created, used, left unused and then “die” (ie, depending on their “life times”).
  • This is because the problem being averted is multiple variables mangling the same data. So what a variable or reference can or cannot do depends on what other related variables exist and what they are able to do.
  • Generally, these “abilities” can be thought of as “permissions”.
    • “Ownership”: the permission a variable has to move its ownership to another variable or “kill” the “owned” data/memory when the variable falls out of scope.
    • “Read”: permission to read the data
    • "Write": permission to mutate the data or write to the referenced heap memory
  • As an example of permissions changing: a variable loses “ownership” of its data when a reference to it is created. This prevents a variable from taking its data into another scope and then potentially “dying” and being deallocated for a reference to that memory to then be used and read or write random/arbitrary data from the now deallocated memory.
  • Similarly, a variable that owns its data/memory/value will lose all permissions if a mutable reference (or unique reference) is made to the same data/variable. This is why a mutable reference is also known as a unique reference.
  • Permissions are returned when the reference(s) that altered permissions are no longer used, or “die” (IE, their lifetime comes to an end).

<span style="font-style:italic;color:#969896;">// >>> References remove ownership permissions
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">take_ownership_heap</span><span style="color:#323232;">(</span><span style="font-weight:bold;color:#a71d5d;">_</span><span style="color:#323232;">: Vec<</span><span style="font-weight:bold;color:#a71d5d;">i32</span><span style="color:#323232;">>) {}
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> k </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#323232;">vec![</span><span style="color:#0086b3;">1</span><span style="color:#323232;">, </span><span style="color:#0086b3;">2</span><span style="color:#323232;">, </span><span style="color:#0086b3;">3</span><span style="color:#323232;">];
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> k_ref </span><span style="font-weight:bold;color:#a71d5d;">= &</span><span style="color:#323232;">k;
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// ERROR
</span><span style="color:#62a35c;">take_ownership_heap</span><span style="color:#323232;">(k);
</span><span style="font-style:italic;color:#969896;">// Cannot move out of `k` into `take_ownership_heap()` as it is currently borrowed
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> k1 </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> k_ref[</span><span style="color:#0086b3;">0</span><span style="color:#323232;">];
</span><span style="font-style:italic;color:#969896;">// if the shared reference weren't used here, rust be happy...
</span><span style="font-style:italic;color:#969896;">// as the reference's lifetime would be considered over
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// >>> Mutable reference remove read permissions
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let mut</span><span style="color:#323232;"> m </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">13</span><span style="color:#323232;">;
</span><span style="color:#323232;">
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> m_mut_ref </span><span style="font-weight:bold;color:#a71d5d;">= &mut</span><span style="color:#323232;"> m;
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// ERROR
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> n </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> m </span><span style="font-weight:bold;color:#a71d5d;">* </span><span style="color:#0086b3;">10</span><span style="color:#323232;">;
</span><span style="font-style:italic;color:#969896;">// CANNOT read or use `m` as it's mutably borrowed
</span><span style="font-weight:bold;color:#a71d5d;">*</span><span style="color:#323232;">m_mut_ref </span><span style="font-weight:bold;color:#a71d5d;">+= </span><span style="color:#0086b3;">1</span><span style="color:#323232;">;
</span><span style="font-style:italic;color:#969896;">// again, must use the mutable reference here to "keep it alive"
</span>

Lifetimes are coming


<span style="font-weight:bold;color:#a71d5d;">fn </span><span style="font-weight:bold;color:#795da3;">first_or</span><span style="color:#323232;">(strings: </span><span style="font-weight:bold;color:#a71d5d;">&</span><span style="color:#323232;">Vec<String>, default: </span><span style="font-weight:bold;color:#a71d5d;">&</span><span style="color:#323232;">String) -> </span><span style="font-weight:bold;color:#a71d5d;">&</span><span style="color:#323232;">String {
</span><span style="color:#323232;">    </span><span style="font-weight:bold;color:#a71d5d;">if</span><span style="color:#323232;"> strings.</span><span style="color:#62a35c;">len</span><span style="color:#323232;">() </span><span style="font-weight:bold;color:#a71d5d;">> </span><span style="color:#0086b3;">0 </span><span style="color:#323232;">{
</span><span style="color:#323232;">        </span><span style="font-weight:bold;color:#a71d5d;">&</span><span style="color:#323232;">strings[</span><span style="color:#0086b3;">0</span><span style="color:#323232;">]
</span><span style="color:#323232;">    } </span><span style="font-weight:bold;color:#a71d5d;">else </span><span style="color:#323232;">{
</span><span style="color:#323232;">        default
</span><span style="color:#323232;">    }
</span><span style="color:#323232;">}
</span><span style="color:#323232;">
</span><span style="font-style:italic;color:#969896;">// Does not compile
</span><span style="color:#323232;">error[</span><span style="color:#0086b3;">E0106</span><span style="color:#323232;">]: missing lifetime specifier
</span><span style="color:#323232;"> </span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#323232;">-> test.rs:</span><span style="color:#0086b3;">1</span><span style="color:#323232;">:</span><span style="color:#0086b3;">57
</span><span style="color:#323232;">  </span><span style="font-weight:bold;color:#a71d5d;">|
</span><span style="color:#0086b3;">1 </span><span style="font-weight:bold;color:#a71d5d;">| fn </span><span style="font-weight:bold;color:#795da3;">first_or</span><span style="color:#323232;">(strings: </span><span style="font-weight:bold;color:#a71d5d;">&</span><span style="color:#323232;">Vec<String>, default: </span><span style="font-weight:bold;color:#a71d5d;">&</span><span style="color:#323232;">String) -> </span><span style="font-weight:bold;color:#a71d5d;">&</span><span style="color:#323232;">String {
</span><span style="color:#323232;">  </span><span style="font-weight:bold;color:#a71d5d;">|                      ------------           -------     ^</span><span style="color:#323232;"> expected named lifetime parameter
</span><span style="color:#323232;">  </span><span style="font-weight:bold;color:#a71d5d;">|
</span><span style="color:#323232;">  </span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#323232;"> help: this function</span><span style="font-weight:bold;color:#a71d5d;">'s return type </span><span style="color:#323232;">contains a borrowed value, but the signature does not say whether it is borrowed from `strings` or `default`
</span>
  • In all of the above, the dynamics of what permissions are available depends on how long a variable is used for, or its “lifetime”.
  • Lifetimes are something that rust detects by inspecting the code. As stated above, it can be a bit cautious or course in this detection.
  • This can get to the point where you will need to explicitly provide information as to the length of a variable’s lifetime in the code base. This is done with lifetime annotations and are the 'as in the following code: fn longest<'a>(x: &'a str, y: &'a str) -> &'a str.
  • They won’t be covered here … but they’re coming.
  • Suffice it to appreciate why this is a problem needing a solution, with the code above as an example:
    • the function first_or takes two references but returns only one reference that will, depending entirely on runtime logic, depend on one of the two input references. IE, depending on what happens at runtime, one of the input references have a longer lifetime than the other. As Rust cannot be sure of the lifetimes of all three references, the programmer has to provide that information. A topic for later.
maegul,
@maegul@lemmy.ml avatar

2. Any persistent gripes, difficulties or confusions?

I’m not entirely sure why, but the whole Double-Free issue never quite sunk in from chapter 4. It’s first covered, I think here, section 4.3: Fixing an Unsafe Program: Copying vs. Moving Out of a Collection

I think it was because the description of the issue kinda conflated ownership and the presence or absence of the Copy trait, which isn’t covered until way after chapter 4. Additionally, it seems that the issue mechanically comes down to whether the value of a variable is actually a pointer to a heap allocation or not (??)

It was also a behaviour/issue that tripped me up in a later quiz, in an ownership recap quiz in chapter 6 where I didn’t pick it up correctly.

Here’s the first quiz question that touches on it (see Q2 in The Book here, by scrolling down).

Which of the following best describes the undefined behavior that could occur if this program were allowed to execute?


<span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> s </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">String</span><span style="color:#323232;">::from(</span><span style="color:#183691;">"Hello world"</span><span style="color:#323232;">);
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> s_ref </span><span style="font-weight:bold;color:#a71d5d;">= &</span><span style="color:#323232;">s;
</span><span style="font-weight:bold;color:#a71d5d;">let</span><span style="color:#323232;"> s2 </span><span style="font-weight:bold;color:#a71d5d;">= *</span><span style="color:#323232;">s_ref;
</span><span style="color:#323232;">println!(</span><span style="color:#183691;">"</span><span style="color:#0086b3;">{s2}</span><span style="color:#183691;">"</span><span style="color:#323232;">);
</span>

For those not clear, the issue, if this code were permitted to execute, is that s2 would be a pointer to the same String that s points too. Which means that when deallocations occur as the scope ends, both s and s2 would be deallocated, as well as their corresponding memory allocations on the heap. The second such deallocation would then be of undefined content.

I find this simple enough, but I feel like the issue can catch me whenever the code or syntax obscures that a pointer would be copied, not some other value, like in the re-cap quiz in chapter 6 that I got wrong and linked above.

maegul, (edited )
@maegul@lemmy.ml avatar

4. Any hard learnt lessons? Or tried and true tips?

A basic lesson or tip from a discussion in this community (link here):

PS: Abso-fucking-lutely just clone and don’t feel bad about it. Cloning is fine if you’re not doing it in a hot loop or something. It’s not a big deal. The only thing you need to consider is whether cloning is correct - i.e. is it okay for the original and the clone to diverge in the future and not be equal any more? Is it okay for there to be two of this value? If yes, then it’s fine.

IE, using copy/clone as an escape hatch for ownership issues is perfectly fine.


Another one that helps put ownership into perspective I think is this section in the Rustonomicon on unsafe rust, and the section that follows:

There are two kinds of reference:

  • Shared reference: &
  • Mutable reference: &mut

Which obey the following rules:

  • A reference cannot outlive its referent
  • A mutable reference cannot be aliased

That’s it. That’s the whole model references follow.

Of course, we should probably define what aliased means.


<span style="color:#323232;">error[E0425]: cannot find value `aliased` in this scope
</span><span style="color:#323232;"> --> <rust.rs>:2:20
</span><span style="color:#323232;">  |
</span><span style="color:#323232;">2 |     println!("{}", aliased);
</span><span style="color:#323232;">  |                    ^^^^^^^ not found in this scope
</span><span style="color:#323232;">
</span><span style="color:#323232;">error: aborting due to previous error
</span>

Unfortunately, Rust hasn’t actually defined its aliasing model. 🙀

While we wait for the Rust devs to specify the semantics of their language, let’s use the next section to discuss what aliasing is in general, and why it matters.


Basically it highlights that rust’s inferential understanding of the lifetimes of variables is a bit coarse (and maybe a work in progress?) … so when the compiler raises an error about ownership, it’s being cautious (as The Book stresses, unsafe code may not have any undefined behaviour).

It helps I think reframe the whole thing as not being exclusively about correctness but just making sure memory bugs don’t happen


Last lesson I think I’ve gained after chapter 4 was that the implementation and details of any particular method or object matter. The quiz in chapter 6 (question 5) I’ve mentioned is I think a good example of this. What exactly the Copy and Clone trait are all about too … where I found looking into those made me comfortable with the general problem space I was navigating in working with ownership in rust. Obviously the compiler is the safe guard, but you don’t always want to get beaten over with ownership problems.

maegul,
@maegul@lemmy.ml avatar

Yep. I’m with you on all of that!

The pitching of The Book is definitely off (this my attempt to write a basic intro to the borrow checker, just to see where my own brain was at but also out of a somewhat fanciful interest in what a better version could look like).

I wonder if the lack of C or assembly equivalents is because the internals aren’t stable??

And yea, optimising data copies on the first go seems to be a trap (for me too!)

Do you know if there are any good tools for analysing the hot spots of data copying?

maegul,
@maegul@lemmy.ml avatar

It really is a decent album once you get past the initial knee jerk reaction to it lol

Haha yea … a Kerry King solo album certainly would bring that out in people.

maegul,
@maegul@lemmy.ml avatar

Huh!

My impression of Godzilla x Kong, as someone who’s generally enjoyed that franchise, is that it’s basically reached a sort of “strangely calm and abstract animated cartoon vibe”. Which I’m probably down for, but which is also probably just not as entertaining as many would expect.

maegul, (edited )
@maegul@lemmy.ml avatar

I’m not sold on the idea of “imperative programming without any shared mutable state at all”. Maybe I just can’t accurately imagine what that would look like in practice.

Neither.

for tasks that are not inherently unsuited to Rust’s current state

Curious where you draw the line on this.

This is the single “deepest” lesson that I feel like I’ve learned about Rust so far. Lifetimes, stumbled upon while trying to avoid (runtime) garbage collection, are in fact a more general tool for delimiting behavior/causality in programs.

Interesting you use the word “causality” there … do you have anything in particular in mind or are you generally thinking about trying to nail down what the cause of a bug may be? I liked the phrase from the article (which you quote): you never need to worry about “spooky action at a distance.” (emphasis mine).

maegul,
@maegul@lemmy.ml avatar

Yea nice.

I’d kinda developed the same attitude but never really thought about it in terms of “causality” as you put it. Instead I had more of a “clean code” or “efficiency” framing, but I like yours much better.

maegul,
@maegul@lemmy.ml avatar

Agreed

The read through of chapter 4 definitely feels like it helped cement some parts of lifetimes & ownership in my understanding.

Yea I had a similar feeling. I haven’t been using rust recently (for reasons), but when I got through chapter 4 I was quite happy and somewhat comfortable to just start hacking and looking up or reading about things as I needed them, as the borrow checker definitely seems like the most opaque and painful part of the language (so far!)

  • All
  • Subscribed
  • Moderated
  • Favorites
  • megavids
  • mdbf
  • ngwrru68w68
  • InstantRegret
  • magazineikmin
  • thenastyranch
  • rosin
  • khanakhh
  • tacticalgear
  • Youngstown
  • slotface
  • Durango
  • kavyap
  • DreamBathrooms
  • JUstTest
  • ethstaker
  • GTA5RPClips
  • modclub
  • tester
  • anitta
  • osvaldo12
  • cisconetworking
  • everett
  • cubers
  • Leos
  • provamag3
  • normalnudes
  • lostlight
  • All magazines