3 ms·
It all gets more complicated when you want to pass more than one secret parameter, or the function already returns a Secret - now you need a monad. The key feat
by yccs27 4y ago
It all gets more complicated when you want to pass more than one secret parameter, or the function already returns a Secret - now you need a monad. The key feature seems to be that the code does not need 'map' or anything, the secrecy flag is propagated regardless.
- grantjpowell 4y ago> now you need a Monad "need a Monad" sounds scary but in practice it looks like this impl<T> Secret<T> { pub fn map<U>(&self, func: impl FnOnce(&T) -> U) -> Secret<U> { Secret(func(&self.0)) } pub fn flat_map<U>(&self, func: impl FnOnce(&T) -> Secret<U>) -> Secret<U> { func(&self.0) } } If you need an escape hatch for something more complicated, you could provide an api to that impl<T> Secret<T> { pub unsafe fn reveal(&self) -> &T { &self.0 } }
- yccs27 4y agoMy point, which I didn’t express well there, was about the call side: How do you call func(param1: A, param2: B) -> C with both parameters being secrets (secret1: Secret<A>, secret2: Secret<B>)? In Rust, it‘s flat_map(secret1, |param1| map(secret2, |param2| func(param1, param2) ) ) or with do_notation at least a bit cleaner do! { param1 <- secret1; param2 <- secret2; Secret(func(param1, param2)); } whereas Rune manages it with func(secret1, secret2)