Niko raises an interesting point about unsafe in the ongoing discussion about await:
This makes me wonder if a variant postfix syntax for unsafe that takes an expression rather than a block might be useful; building on that, as an analogy to futures, I wonder if it might be reasonable to support a monad-like way of performing unsafe operations as some kind of first-class citizen, permitting the creation of special unsafe closures.
An example
My knee-jerk response is that this would not be a good idea, because it would obscure unsafe code somewhat, and because it would separate the unsafe code itself from the location where the keyword is used. But just as a thought experiment, here's what it could look like, introducing a dummy keyword and type:
fn read_mem(ptr: *const u32) -> Unsafe<Fn()->u32> {
ptr.unsafe(core::ptr::read)
}
Here, unsafe is a postfix keyword (maybe?) that creates an object of type Unsafe. The keyword operates on an expression and takes a callable as an argument; the callable must be able to accept the expression as an argument. Unsafe itself is the "unsafe monad", which supports an interface something like this:
fn get_val(op: Unsafe<impl Fn()->u32>) -> u32 {
op.do_unsafe
}
Here, do_unsafe is a postfix keyword, like .await.
Note, of course, that Unsafe<FnOnce> and Unsafe<FnMut> would also exist.
If the user wanted to execute the unsafe bit immediately instead of constructing an Unsafe object and postponing the unsafe operation, then the keywords could be used in conjunction, like so:
ptr.unsafe(std::mem::read).do_unsafe
Here is some Playground code demonstrating, essentially, the "desugared" version of the above example (with an extra unsafe that wouldn't be necessary if this feature were adopted).