4 ms·
> In a library you want to check preconditions at the external boundary so the actual implementation can proceed knowing there are no dangling pointers, or nega
by LegionMammal978 3y ago
> In a library you want to check preconditions at the external boundary so the actual implementation can proceed knowing there are no dangling pointers, or negative numbers, or whatever the internal assumptions may be. Depending on the caller to do the check defeats the purpose.
I think the idea is to instead address this with a type-safe interface, designed so that the external boundary physically cannot receive invalid input. The caller would then be responsible for its own if statements when constructing the input types from possibly-invalid raw values.
> Also in many cases you would need to violate encapsulation/abstraction. Consider a stupid case: `bool cache_this (T obj)`. Let the cache manager itself check to see if the object is already there as it can probably touch the object fewer times.
I don't see the suggestion as encouraging such a thing: the "cache_this" check should only ever be performed when it's known for certain that the user wants to access the cached object, so the entry point of the cache abstraction acts as a kind of boundary that the if statement depends on. And the if statement clearly shouldn't be pushed above its own dependency.
- hedora 3y agoIn cases where that doesn't make sense: let f = Some(get_a_u16()); foo(f); ... func foo(f: u16) -> u16 { match f { None => 0, Some(f) => f * 1234 } } I'd expect any reasonable compiler to include enough link time optimization and dead code elimination to compile the whole mess down to a single multiply instruction.
- LegionMammal978 3y agoI don't see what you're tying to show with your example? The typical case is, you start with a raw type in the caller (u16), and then you create a derived type (Option<MultipliedU16>) as a result of validation. Also, you'd ideally want to handle overflow errors in the multiplication, especially with something as small as a u16. (And in case it helps anyone, for a trivial function to be inlined across crates in Rust, either the function must be marked with #[inline], or a special LTO option must be explicitly set in the Cargo profile. So often it's a good idea to mark all public trivial utility functions in a crate with #[inline].)
- hedora 3y agoIn my example, passing in none returns a value, not an error, so the intent is that it makes sense for that API to handle the None case in normal operation. However, in situations where the compiler can infer the argument is never None, it can remove the branch. (Yes, that function should probably handle overflow explicitly, but that wasn't the point.)
- gumby 3y ago> I think the idea is to instead address this with a type-safe interface, designed so that the external boundary physically cannot receive invalid input. Ah, an idea that people have broken their picks on for 50 years. We will pay out bonuses to employees who worked at least 9 months last year. Actually current employees and former employees. I should create a special type for this case and then depend on the caller to construct such types only for qualifying recipients? That’s just “moving the if” back into the caller. Any responsible developer would validate those entries at the interface…and is it complete?
- LegionMammal978 3y agoThs idea is, we wouldn't be "depending on the caller": the constructor itself would indicate failure instead of producing an object if the data is invalid, so the caller can't mess up without completely violating the abstraction. So we would still be doing the validation "at the interface". It's just that the interface would be split into two separate functions, one checking for qualification and another operating on qualified employees. Also, an alternative would be to push the for loop down into the interface, so that it enumerates each employee, immediately filters them for qualification, and then performs whatever other work is needed for paying out. (It could even include a caller hook to perform additional filtering before paying out.)