You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
With the current safe API we check if the key is valid every time we make an operation and we need to handle the error case for every single operation, even if we have already checked that the key is safe. It also forces us to delay the verification until the very last moment.
My suggestion is to decouple the verification from the usage by adding a new opaque wrapper type SafeKey that can only be constructed by verifying that the key is safe. The new API could look something like this:
moduleIntDict.Safe.Keyexposing (SafeKey, verify, toInt)
-- This type is evidence that the key has been verified-- (The constructor should not be exposed)type SafeKey=SafeKeyInt{- | Check if a key is valid -}verify:Int->MaybeSafeKeyverify key =if isValidKey key thenJust(SafeKey key)elseNothingtoInt:SafeKey->InttoInt (SafeKey key)=
key
moduleIntDict.Safeexposing (..)
importIntDictimportIntDict.Safe.KeyasKeyexposing (SafeKey)
insert:SafeKey->v->IntDictv->IntDictvinsert k v dict =IntDict.insert (Key.toInt k) v dict
-- etc...
We haven't really lost anything in terms of verbosity, but we have won in flexibility and separation of concerns, since we can now verify the keys at the edges of the program, then store and use the verified keys everywhere else and only handle errors once if we want to.
I am aware that this is a very much breaking change, so I should probably put this in a separate library instead, at least initially. However, if you think it is worthwhile to change the API here, I can write up a pull request for use in the next major version.
[note 1]: This pattern can be seen as an extension of the make impossible states impossible idea, in that we make invalid parameters to the functions impossible by verifying them on beforehand and thus eliminating the need for a Result type in the output. It is also related to Hoare logic which analyzes programs in terms of preconditions and postconditions.
The text was updated successfully, but these errors were encountered:
With the current safe API we check if the key is valid every time we make an operation and we need to handle the error case for every single operation, even if we have already checked that the key is safe. It also forces us to delay the verification until the very last moment.
My suggestion is to decouple the verification from the usage by adding a new opaque wrapper type
SafeKey
that can only be constructed by verifying that the key is safe. The new API could look something like this:You would use it like this:
Contrast this with the old version
We haven't really lost anything in terms of verbosity, but we have won in flexibility and separation of concerns, since we can now verify the keys at the edges of the program, then store and use the verified keys everywhere else and only handle errors once if we want to.
I am aware that this is a very much breaking change, so I should probably put this in a separate library instead, at least initially. However, if you think it is worthwhile to change the API here, I can write up a pull request for use in the next major version.
[note 1]: This pattern can be seen as an extension of the make impossible states impossible idea, in that we make invalid parameters to the functions impossible by verifying them on beforehand and thus eliminating the need for a Result type in the output. It is also related to Hoare logic which analyzes programs in terms of preconditions and postconditions.
The text was updated successfully, but these errors were encountered: