3 ms·
The Unix kernel API only returns a numeric error code, no additional information. Nine times out of ten¹ the file that wasn't found is the file that you just tr
by thristian 3y ago
The Unix kernel API only returns a numeric error code, no additional information. Nine times out of ten¹ the file that wasn't found is the file that you just tried to open or rename or whatever, so a language runtime can make a copy of that and attach it to their error representation, but (a) that's more work so it gets shunted out of the MVP, and (b) it requires allocating memory to store the copy, and some languages (like Rust) do not want silent memory allocation as a default behaviour.
¹: The one time out of ten is things like a script with a #! line that refers to a file that doesn't exist. The file you asked for (the script) definitely exists, but you'll get a file-not-found error if you ask the kernel to run it. Modern versions of bash seem to detect this situation and display a more helpful error message, but this is specific to bash, not other shells or languages.
- deleted 3y ago[deleted]
- littlestymaar 3y ago> (b) it requires allocating memory to store the copy, and some languages (like Rust) do not want silent memory allocation as a default behaviour. There's no need for an allocation: you already have the path allocated somewhere since you're making the call. So you could just have a pointer to that path in the error. That would obviously be very dangerous in C, because then you'd have to be careful not to have your error outlive your allocated path, but in Rust you'd have a lifetime annotation on your Error guaranteeing that your Error does not outlive your allocated path.
- duped 3y ago> but in Rust you'd have a lifetime annotation on your Error guaranteeing that your Error does not outlive your allocated path. That's a really heavy constraint that doesn't work in practice - errors usually bubble up past the scope of the arguments of whatever failed.
- littlestymaar 3y agoThis design would force you to make a choice: if you want to bubble the error up[1], then you either: - discard the file path - allocate This way, you control the performance/UX trade-off. And it doesn't require much work: it's just a From implementation to add to your error enum. [1] only higher than the actual owned path actually.
- insanitybit 3y agoWhat you're talking about is very practical imo and likely the right solution, but unfortunately would be a breaking change (you can't just add a lifetime annotation to the error).
- littlestymaar 3y agoIt's not even my biggest complaint about std::fs, the entire module feels very much not like the rest of Rust and way too close to the underlying libc (for legitimate reasons: they couldn't release Rust 1.0 without file access and likely didn't have much bandwidth to work on an alternative API). Maybe some day Rust will support multiple versions of the stdlib (in a compatible way, like what's done with editions) but until then we'll have to work with this half-baked corner of the language.
- voidnap 3y ago> you'd have a lifetime annotation on your Error guaranteeing that your Error does not outlive your allocated path This has implications that are obviously undesirable, like prohibiting returning errors borrowing file paths allocated on the stack.
- littlestymaar 3y agoNo, if you need your error to outlive the path, then you can create a dedicated error that hold the path itself. This way it could lead to an allocation, but only when you actually need it. In your particular example you could memcopy the path in the Error, without allocating at all (but you may also want to box the path instead if the path made the enum size too big).
- voidnap 3y ago> can create a dedicated error that hold the path itself. Right making the standard library's error type far less useful if you have to start writing your own error types lol. That's such an obnoxious design. The way it is now you can write programs that return and handle io errors just fine when they don't care about the path or other arguments. Your suggestion would require those programs to make a dedicated error type to unabstract away what is essentially a thin wrapper around errno. The value of a `std::io::Error` is still obviously appealing.
- duped 3y ago> The one time out of ten is things like a script with a #! line that refers to a file that doesn't exist. More generally, the interpreter doesn't exist. For a script with a shebang that's whatever is under the shebang. For executables it's whatever is in the PT_INTERP header in the binary (in ELF, or whatever the equivalent is for PE/Mach-O). For example you might have an ELF binary with PT_INTERP set to /usr/lib/ld-linux.so when it's actually /lib/x86_64-unknown-linux-gnu/ld-linux.so. You'll get a "exec: File not found" error, even if all the files you think you need exist. The loader itself is what's missing.