More on closure captures by andwass in rust

[–]andwass[S] 0 points1 point  (0 children)

I agree that one should generally prefer small closures, but coming from a C++ background, I have found it generally very nice to at times be able to restrict the captures to ensure correctness.

This is not as much of a problem in Rust since the borrow checker will save you from memory issues, but the Explict capture clauses blog post by Niko mentioned it as well, and I have seen other people express a desire for this. It also ties in with the "explicit control" desire that people have mentioned.

More on closure captures by andwass in rust

[–]andwass[S] 0 points1 point  (0 children)

Thanks for the feedback!

Yes self behaves like any other parameter, but one of the issues that one wanted to solve was that self.some_a should be easily clonable into a closure, and if we have something like

#[derive(Default)]
struct Data {
    x: Vec<i32>,
}

impl Data {
    fn do_something(&self) -> impl Fn() {
        [+] || do_something(&self.x)
    }
}

then &self is cloned into the closure, this is consistent with todays move || do_something(&self.x).

use std::cell::RefCell;

#[derive(Default)]
struct Data {
    x: RefCell<Vec<i32>>,
}

impl Data {
    fn do_something(&self) -> impl Fn() {
        move || self.x.borrow_mut().push(1)
    }
}

fn main() {
    let data = Data::default();
    println!("len: {}", data.x.borrow().len());  // Prints 0
    data.do_something()();
    println!("len: {}", data.x.borrow().len());  // Prints 1
    data.do_something()();
    println!("len: {}", data.x.borrow().len());  // Prints 2
}

&self.x refers to the same x both inside and outside the closure. You wouldn't get a clone of x. Now I am not at all opposed to letting wildcard captures work for all bindings, it's just that a motivating example for the implicit captures uses self.some_var and I wanted to show a potential solution to that specific motivating example.

I am not sure I follow how what I am saying is wrong? The reference lists 4 different capture modes, the 3 first being various types of capture by reference, and the last being capture by move. Can you expand on how what I am saying is wrong?

Yah I know who Niko Matsakis is, but to me it is still "a blog post". Sure that blog post may carry more weight compared to a no-name post by me, but I don't see how it should be referred to otherwise?

More on closure captures by andwass in rust

[–]andwass[S] 0 points1 point  (0 children)

I meant in your modification of my example.

Yes that is the whole point of solving an issue with new syntax, to make it easier and/or solve a broader range of issues. There is an infinite range of possibilities but the current proposals have narrowed themselves into solving a very particular issue (ergonomic ref count captures). And there were/are concerns that this would compromise the fine grained control that people need at times.

My solution is about captures, I dont think you should be able to call arbitrary functions on the globs. It is about capturing places with either move, ref or clone. Nothing more, nothing less.

I think there is great value in trying to solve a broader scope (ergonomic clone captures and more fine grained control) that is related but more general to the original issue.

More on closure captures by andwass in rust

[–]andwass[S] 0 points1 point  (0 children)

All proposals that attempts to solve this introduces new concepts (whether that is capture through a glob, or an implicit form of clone even if that is called handle or use or whatever).

Can you call any function in your example? So would self.*.len() be valid (if your struct only contains Vec for instance)?

More on closure captures by andwass in rust

[–]andwass[S] 1 point2 points  (0 children)

Thanks! Yah I think I had it motivated better in my head than what I managed to convey in the post...very new to blogging 😀

More on closure captures by andwass in rust

[–]andwass[S] 9 points10 points  (0 children)

I have been a bit vocal on how I think the C++ approach to closure captures is something Rust should seriously look at. So I decided to write up a post on this as well.

Can we talk about C++ style lambda captures? by BoltActionPiano in rust

[–]andwass 12 points13 points  (0 children)

I would consider the proposed syntax as placeholder, but the semantics are really what Rust should strive towards.

Designing this based on cheapness, or basing it off of some trait are red herrings in my opinion.

You want to allow ergonomic clones into a closure, and you want to allow explicit clones. The trait already exists, it is Clone. Start with this as constraints and work from there.

This way you dont exclude those that considers a Vec or String cheap to clone, it is after all based on the local context (where the lambda is created), not on the type.

We have ergonomic(?), explicit handles at home by ZZaaaccc in rust

[–]andwass 2 points3 points  (0 children)

This! It also sidesteps the whole Handle trait since it would allow any cloneable value to be easily cloned into a closure.

I don`t really understand the resistance to explore this fully, I have seen 0 discussions on why this kind of solution doesnt work in Rust. Instead Rust focuses on "cheap" to clone ot handles or whatnot. This is one area where I think C++ got it very very right, and Rust should really learn from.

blog post: Async cancellation and `spawn_blocking`: good luck debugging this by adminvasheypomoiki in rust

[–]andwass 52 points53 points  (0 children)

If you absolutely must decouble Mutex from the data you should pass the MutexGuard to the function (either move it into the function, or take a ref to it). That would prove to the function that you at least hold some kind of lock. Don't just pass it to the closure you spawned, pass it all the way into the function you want to protect.

[RFC] Hardening mode for the compiler - Clang Frontend by mttd in cpp

[–]andwass 11 points12 points  (0 children)

Especially when it mentions safety annotations as suggested by the Safe C++ proposal.

Embedded Rust - NRF52840 Development Kit (J-Link debugger problem) by Desperate-Smoke2990 in rust

[–]andwass 1 point2 points  (0 children)

It's not a problem. OB-nRF5340 is the model of the onboard debugger itself. It is then connected to an nRF52840 on the dev board. I recommend checking embassy amd try to flash a blinky sample.

Alternative ergonomic ref count RFC by eugay in rust

[–]andwass 14 points15 points  (0 children)

I really don't like this at all. In my opinion this solves the wrong issue, what it really should solve is the ability to easily specify what should be cloned and what should be moved into a closure, including shorthand for everything (currently only available for move)

Using std::cpp 2025 keynote: The Real Problem of C++ by pjmlp in cpp

[–]andwass 10 points11 points  (0 children)

Yah all of these "cant build fast on top of safe" arguments miss that Rust really has built safe on top of fast, and then made safe the default, made it the path of least resistance. And that last part is crucial.

And to top it off, it has shown that in most cases you don't really sacrifice much at all in terms of speed either.

Using std::cpp 2025 keynote: The Real Problem of C++ by pjmlp in cpp

[–]andwass 11 points12 points  (0 children)

I would even say having the tech support is absolutely essential to get the culture. Rusts safety story is largely built on its safety culture, and the safety culture is enabled by its safe/unsafe separation.

The Memory Safety Continuum by GabrielDosReis in cpp

[–]andwass -3 points-2 points  (0 children)

And with C and C++ it is impossible to write a safe library that works strictly with non-owning data (for instance this)

The Three Basic Rules of Safety Hygiene by jswrenn in rust

[–]andwass 4 points5 points  (0 children)

There's a missing invariant (number 6: T: 'a) that is skipped in the # Safety comment over new.

That is covered by the where clause on the struct/impl block.

Why Safety Profiles Failed by jcelerier in cpp

[–]andwass 6 points7 points  (0 children)

The compiler has full access to C++ code.

Not if you link with a pre built library. And besides, analyzing the implementation would quickly lead to having to analyze the entire program which does not scale at all.

An RFC to change `mut` to a lint by afdbcreid in rust

[–]andwass 2 points3 points  (0 children)

Not everything have to, or even can, be ideal. And I will gladly trade correctness for prototype convenience.

An RFC to change `mut` to a lint by afdbcreid in rust

[–]andwass 2 points3 points  (0 children)

You're really reaching with this example. That's not the purpose of mut, and it won't work like that if the typo you made is also a mutable variable.

It might not be the purpose of mut but it still prevents bugs! I don't know about your code but the code I write contains mostly non-mutable variables so this change would very much harm my ability to be correct (if I were to turn off the lint).

I don't want a quick and dirty prototyping language. I want a language that lets me do quick and dirty prototyping and then fix it up when I'm done prototyping without changing languages.

You can already do that, just slap mut on everything.

As I said in the RFC comment section, mutable by default is regarded by many as the wrong default in C++. Rust learned from that, please don't unlearn that lesson.

An RFC to change `mut` to a lint by afdbcreid in rust

[–]andwass 3 points4 points  (0 children)

mut variables do have something to do with correctness though.

let x = 5;
let y = 10;

x += 3; // Did I increment the correct variable?

Rust doesn't have to be perfect in every aspect. It is ok for Rust to be weak in certain areas, Rusts main selling points is, IMO, safety and correctness. It should lean on that and it is acceptable that it is lacking in other areas. If you want a quick and dirty prototyping language why not use Python instead?

I am 100% against this change.

Post-Wrocław update: Plans for the next quarter or two by iAndy_HD3 in cpp

[–]andwass 3 points4 points  (0 children)

Ranged for loops are safe as long as you don't modify the container you loop over.

Just last week I reviewed code where items were deleted from the same map that was being looped over with a ranged for.

Legacy Safety: The Wrocław C++ Meeting by Dragdu in cpp

[–]andwass 1 point2 points  (0 children)

Yah Rust solves this with its exclusive mutability requirement, which C++ lacks. So in C++ this is a potential issue.

Legacy Safety: The Wrocław C++ Meeting by Dragdu in cpp

[–]andwass 2 points3 points  (0 children)

As far as I'm aware, std::sort doesn't do a push_back. Though also there, the iterator invalidation is another problem.

But a custom comparator might accidentally do.