5 ms·
Very cool to see the start of official support. Unfortunately it looks like it requires unsafe { } for now, though maybe it's intended as a low-level foundation
by brundolf 6y ago
Very cool to see the start of official support. Unfortunately it looks like it requires unsafe { } for now, though maybe it's intended as a low-level foundation on which a higher-level, safer API can be built
- _zamorano_ 6y agoWell, the Windows API is "unsafe" by design, is C-based, you pass pointers around, datatype sizes, etc... How can you avoid "unsafe" in this scenario? You're asking for a new framework or an API rewrite
- brundolf 6y agoThe domain itself isn't fundamentally unsafe, only the way the C API has been designed. You're right that meaningfully different abstractions (instead of a one-to-one translation) may be required to make a safe API, which is why I suggested that could be a possibility.
- Spivak 6y agoBut that wouldn't eliminate the need for unsafe code at the border. All ffi calls are inherently unsafe to Rust. You can design the cleanest nicest safest C api in the world but it's still unsafe as far as Rust is concerned.
- MereInterest 6y agoYes, but those unsafe blocks can be wrapped into the library. "Unsafe" doesn't inherently mean "bad", it just means that the programmer is explicitly taking the burden of making sure that the normal invariants still hold. So long as the library authors ensure that, then the "unsafe" blocks remain within the library and don't need to be worried about by the users of the library. On the other hand, if a library pushes that additional responsibility to me, it makes me more worried.
- brundolf 6y agoYes, but in Rust there are two independent axes here: - Whether or not a library calls unsafe code internally - Whether or not a library declares its public API to be unsafe (https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#calling-an-unsafe-function-or-method https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#call...) It's very much possible (essential, even) to be able to present a safe API to external callers of your code, despite using unsafe code under the hood. In this case you're making a human-checked assertion of safety, which is not guaranteed to be without bugs, but the important thing is that you're minimizing the surface area of un-safety and declaring a contract with your users. You're "stopping the buck" of unsafety rather than passing it on. The parts that really have to be unsafe can enjoy extra scrutiny, and everything else (including the caller's code) can be checked by the compiler. This is not uncommon in the standard library and other low-level libraries. More information here: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#creating-a-safe-abstraction-over-unsafe-code https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#crea...
- josephg 6y agoSure. So this library exposes all of Microsoft’s DLL surface area in an API-native way. That’s important. Now that it’s released, library authors can wrap this with another library, which abstracts over win32, reexposing it in safe rust. Wrapper libraries like that almost certainly won’t cover 100% of the api surface area - there are so many functions in the windows APIs. Anyway, give it time. People will wrap this with safe rust.
- brundolf 6y agoWhich is exactly what I suggested in my original comment :)
- djsavvy 6y agoYes, but if the library abstracts away the unsafe code, then users of the library don't need to write any themselves. This has the advantage of a single point of unsafeness, which can be fixed by the library author/maintainer for all clients.
- amluto 6y agoThis ought to be doable automatically, at least a lot better than the current code: let event = CreateEventW( std::ptr::null_mut(), true.into(), false.into(), std::ptr::null(), ); The .into() is silly but tolerable. But the first parameter is a pointer to a struct, and it’s clear enough from the signature that a reference would work. It could be mut to be on the safe side. (Yes, this involves someone making sure that the API doesn’t retain the pointer.). The last argument is, per the prototype, is a string. Admittedly, the Windows API has a truly horrible idea of what a string is, but surely they could do better than using a pointer.
- steveklabnik 6y agoBoth of these parameters can be null, and references cannot be null, so it is not possible to use references directly without losing some functionality. (They could remove the intos if they wanted to, I agree it feels kind of weird but I'm not actually sure if doing it is better or worse, I am conflicted.)
- Cu3PO42 6y agoIt could very well be Option<&mut T>, though. Personally I think having a 1:1 mapping to the C API is reasonable enough as a first target. It should make porting code easy and referencing the official documentation is probably easiest this way. No matter how many heuristics they apply to make a somewhat more idiomatic mapping, it'll never feel right until it's manually designed to fit with Rust conventions. So I'm okay with it as it is now and can hope for a much thicker abstraction in the future.
- orra 6y agoOption<T> would sensibly solve the nullability?
- steveklabnik 6y agoThere are a few different possibilities, and some of them involve Option, yes. But doing this would still possibly create an annotation burden that the parent is complaining about. My comment was trying to be pretty narrowly scoped to "why not use a reference here." You and your sibling are both right in ways!
- dialamac 6y ago> The domain itself isn’t fundamentally unsafe This makes no sense to me, what you’re saying here. You pass raw pointers to the Windows API for one, for which it makes no safety guarantees. Short of rewriting Windows from scratch I don’t see how this isn’t a fundamentally unsafe domain. Sure you could put more and more wrappers up on top (it’s not an even an issue of one-to-one translation, but how resources such as memory are wrapped), but whatever binding there is pretty much must be unsafe. That it’s possible to write a safe wrapper is kind of obvious.
- Blikkentrekker 6y agoUnix libc is also unsafe, but the Nix crate mostly built a safe, Rust-esque interface around this and abstracted most of the types so that they are safe.
- coldtea 6y ago>Unfortunately it looks like it requires unsafe { } for now Forever, and not "unfortunately" but rather as expected and necessary. Windows API is unsafe (C/C++) itself, and this is a wrapper for it.
- wtetzner 6y agoSure, but safe wrappers can be written around unsafe APIs.
- coldtea 6y agoSince the unsafe APIs directly interface with memory directly, they can bring the whole Rust application and/or put it in unknown state by messing up memory. How could they "patch" that with a wrapper?
- wtetzner 6y ago> Since the unsafe APIs directly interface with memory directly I'm not sure I follow this. Are you saying the unsafe APIs somehow treat memory differently than any other C API that has been wrapped with a safe C wrapper? In any case, I'm saying their current unsafe wrapper can sit under another layer, which provides a safe API. Of course, if there's a bug somewhere in the lower layers, it could still be unsafe, but that's true of all C bindings.
- mmastrac 6y agoLower-level APIs like this are usually unsafe, with second-level libraries providing the safe abstractions over them.
- deleted 6y ago[deleted]
- MaxBarraclough 6y agoSomeone replied and then deleted their comment, but I'll reply to it anyway. They wrote: > This is the safe abstraction! I mean it's a pretty mechanical translation but it's nonetheless as safe as Rust will ever consider it. No, it's not safe. Assuming I understand Rust correctly: if your bindings allow Rust programmers to trigger undefined behaviour even when they restrict themselves to the safe subset of Rust, that means that either your bindings have a defect, or the underlying (wrapped) library has a defect.
- mmastrac 6y agoYes, exactly. It'll be pretty unlikely that raw API bindings can be made safe (even for APIs that just take raw integer handles - you could double-close one and cause corruption/etc).
- simias 6y agoI've seen some discussions on HN in the past where some rustaceans have argued that it's fine to expose raw C APIs in Rust using safe interfaces even if they're fundamentally unsound. I fail completely to understand the reasoning behind that (and I've really tried) but apparently it's still an open debate to some extent.
- MaxBarraclough 6y agoHow disappointing.
- mamcx 6y agoLook this way: All C/C++ programs, all of them, forever, are unsafe by default. Even if a sanitizer, linker, review by the absolute most skilled developer on earth check every line. Because C/C++ is designed without safety. So, Rust can't "believe" the external world is safe because the external world is made unsafe.
- brundolf 6y agohttps://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#creating-a-safe-abstraction-over-unsafe-code https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#crea...
- mamcx 6y agoCorrect. But the thing is only a human could, manually, check the code and consider it safe. Rust can't decide it.
- rendaw 6y agoUnsafe seems like Rust's equivalent of "checked exceptions" - annoying and misdirected red tape. Pretty much all graphics code (ex: vulkan) is nearly 100% unsafe too. The official docs for these libraries just say "wrap everything in an unsafe block". Is marking the apis unsafe going to make people choose an alternative? No. Does it prevent something bad from happening? No. Do users even know what unsafe means, other than that it sounds scary? No. If they did know, would it have imparted useful knowledge to them (that documentation wouldn't have provided more specifically)? I don't think so, for most users.