-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add escape-hatch custom error constructor #85
base: main
Are you sure you want to change the base?
Conversation
Would you mind sharing an example? This error type is shared with purescript-codec-argonaut and it may be a good idea to extend it with a custom constructor. |
@thomashoneyman Yeah sure - a trivial example of the use case would be something like: import Prelude
import Data.Argonaut.Decode (class DecodeJson, decodeJson)
import Data.Argonaut.Decode.Error (JsonDecodeError(..))
import Data.Either (Either(..))
newtype NonEmptyString = NonEmptyString String
instance decodeJsonNonEmptyString :: DecodeJson NonEmptyString where
decodeJson json = do
str <- decodeJson json
case str of
"" -> Left $ CustomError "String must not be empty"
_ -> Right $ NonEmptyString str
Is that what you meant by an example? |
Btw if anyone has ideas for a better name for the constructor than |
Yea, that’s all I meant! I’m trying to get a sense for what may not fit the existing type very well. For example, that NonEmptyString error would usually be something like:
I’d like to walk through issues in codec-argonaut to see what other examples exist also. But it’s probably a good idea to include an escape hatch. |
At the moment if I used the
when printing the error, which looks a bit odd. Alternatively I could just pass in the type name so it reads:
but it's a shame to lose that error information. Appreciate this is very trivial example so not to difficult to figure out what might be the issue with a NonEmptyString. A better example might be something like a date type that you want to decode from a string (e.g. in the format DD/MM/YYYY) - in which case there are potentially a few different ways that the decoding could fail. It seems to me like the More philosophically I think that given the user has the freedom to define their own decoding instances, they should have some sort of option for tailoring their own error messages for their decoders if they choose to (as was possible before |
I agree that it's sensible that an escape hatch exists, and that Either way, I checked with the package set and adding another constructor doesn't break anything. It shouldn't be a change that ripples out in the way that introducing the type in the first place was (few people, if any, are manually pattern-matching on this type). That makes it more palatable to make the change. |
Cool, yeah I must admit I'm a bit ignorant of the history of |
I'm torn - there are definitely times that I want to be a little more precise than just using a type mismatch or unexpected value error, but I'm also wary of adding it because it's open to being overused and losing the structural errors that this helps with in the first place. I did consider using an open variant for the error, as that way it can be extended with additional meaningful constructors, but it adds quite a bit of complexity too. The variant approach seems a bit more like the correct thing to do, but I don't want the weight of it to be offputting either. 🤔 |
Just a note the
should be
|
is it really needed why not |
I believe one more open but still potentially specific error type could be named ParsingFailure. But there still needs to be made a clarification on the difference between TypeMismatch, UnexpectedValue and ParsingFailure, because without it any error could be referred to any of these types.
Maybe this error type could be used for this. |
Perhaps it would be more structured to add a I generally prefer to do parsing and validation in a single step, which is why I run into this issue, but this all makes me wonder if it's even appropriate to have |
How about using a data JsonDecodeError' a
= TypeMismatch String
| UnexpectedValue J.Json
| AtIndex Int JsonDecodeError
| AtKey String JsonDecodeError
| Named String JsonDecodeError
| MissingValue
| Custom a
type JsonDecodeError = JsonDecodeError' Void
printJsonDecodeError ∷ JsonDecodeError → String
printJsonDecodeError = printJsonDecodeError' absurd
printJsonDecodeError' :: forall a. (a -> String) -> JsonDecodeError' -> String
printJsonDecodeError' printCustom = case _
...
Custom a -> printCustom a |
@JordanMartinez I'm on board with your suggested solution here, if you'd like to go forward with it. |
I've just upgraded my package-set and encountered the breaking changes from the new
JsonDecodeError
type. I'm not against having a more specific error type thanString
, but I find the available error constructors are too restrictive when writing my own instances ofDecodeJson
.I propose adding an additional constructor to
JsonDecodeError
for supplying a custom error message, in the case that the errors produced in newDecodeJson
instances aren't covered by the existing constructors.