5 ms·
The Haskell ecosystem uses a very similar convention: unsafe functions have names starting with ‘unsafe’ (or, in one particularly horrible case, ‘accursedUnutte
by bradrn 4y ago
The Haskell ecosystem uses a very similar convention: unsafe functions have names starting with ‘unsafe’ (or, in one particularly horrible case, ‘accursedUnutterable’ [0]). These are generally functions which subvert the type system, so the name acts as an alternate warning.
[0] Documented at https://hackage.haskell.org/package/bytestring-0.11.4.0/docs/Data-ByteString-Internal.html#v:accursedUnutterablePerformIO https://hackage.haskell.org/package/bytestring-0.11.4.0/docs... — incidentally one of the funniest pieces of documentation I’ve ever seen!
- jiggawatts 4y agoRust and C# both use 'unsafe { }' blocks, which can only be enabled by a module-level compiler flag.
- tialaramex 4y agoThere is no such "compiler flag" in Rust, that's only a C# thing. But also more relevantly here, stuff you'd be calling in those Rust blocks tends to have longer names and often calls out the fact it's specifically not checked, e.g. a = b.unchecked_add(c); // Like a C or C++ arithmetic operation if you overflow it's UB. This might be faster. It might not. But if you must have this anyway, that's how n = NonZeroU32::new_unchecked(0); // Unlike new() which returns None because duh, zero isn't non-zero, this results in UB. Not all of them though, for example: v = Vec::from_raw_parts(ptr, len, cap); // Make a Vec, the pointer ptr had better actually be pointing at contiguous memory for exactly cap item-sized slots, the first len of which are in fact legitimately values of the appropriate type, if any of this is wrong that's immediately UB.
- CamJN 4y agoWhile sadly it does not require a flag to enable, at least you can turn it off with: `#![forbid(unsafe_code)]`.
- rezaprima 4y agoAnother correct way to use Hungarian Notation, according to (iirc) Joel Spolsky
- teraflop 4y agoThat doc link is funny, but it's also very frustrating -- you would think that after all those warnings, there would also be some glimmer of information about what sets the accursedUnutterablePerformIO function apart from unsafePerformIO, or at least why it exists, but apparently not. It's clearly important because most of the core functions in Data.ByteString call it. It seems like the authors have decided that the trickiest, most magical parts of their codebase are exactly where they don't care about useful documentation. That seems like a bizarre strategy unless they plan to never let anyone else help with maintenance.
- derefr 4y ago“If you aren’t willing to read the source of the function to learn what it does, we don’t want you anywhere near it. No summary short of the function itself can accurately communicate how much of a fragile hairball of edge-cases this function is, and how many things you have to know about to correctly call it.”
- bradrn 4y agoThis is pretty much correct. For reference, here’s the original documentation (changed in commit 80ff4a3018cd8909abb1d4e0c32f012a523883ec): -- | Just like unsafePerformIO, but we inline it. Big performance gains as -- it exposes lots of things to further inlining. /Very unsafe/. In -- particular, you should do no memory allocation inside an -- 'inlinePerformIO' block. On Hugs this is just @unsafePerformIO@. The commit message notes that ‘We've had a few instances of people being tempted to use it without really understanding the consequences’.
- throw-ru-938 4y agoI wonder why inlining the function makes it that much unsafe.
- Dylan16807 4y agoGood documentation tells you a lot more than the source could. Especially when you're talking about horrific side-effects.
- IgorPartola 4y agoTo me unsafe generally means “memory safety or type safety is disabled”. It doesn’t mean the code can’t run in production. Maybe some just implemented fast inverse square root and tested it manually. danger_force_electrify_fence() is a whole different story.
- bradrn 4y ago> To me unsafe generally means “memory safety or type safety is disabled”. And that is exactly what it means. Unsafe functions in Haskell do run in production. They just subvert type safety (and I believe memory safety too, in the case of accursedUnutterablePerformIO).
- Athas 4y agoEven plain unsafePerformIO is memory-unsafe, as it will let you construct a polymorphic IORef, through which you can implement unsafeCoerce.
- bradrn 4y agoHmm… is that memory-unsafe? I thought that came under the heading of ‘subverting the type system’. Then again, I suppose they’re more or less the same thing in a strongly-typed and pure language like Haskell.
- Athas 4y agoYes, it is very memory unsafe. Subverting the type system often the main source of memory unsafety in most languages. It typically means you can treat an arbitrary integer as a pointer to any other object.