-
Notifications
You must be signed in to change notification settings - Fork 47
decoder implementation that is not dependent on class -> move implementation to Implementation module #74
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
decoder implementation that is not dependent on class -> move implementation to Implementation module #74
Conversation
e48415b
to
7e57801
Compare
why this change: In one project I needed to pass custom decoder function to
breaks error messages but the
doesnt |
You can also write functions of the type I agree there could be value in implementing a But we should do that without introducing typed errors at the same time. Type signatures for the class-based functions should be unchanged. Other maintainers (@garyb) may have a different opinion on whether this would be a welcome change for the library, but I am open to it. |
As an example from the README on the writing functions bit: |
yes, I know, as I told I needed to compose custom decode functions with derived decode functions, but
was breaking error messages (e.g. when that's why I did this pr
yes, I can remove custom error messages from this pr, until decision is not done, and do the same for Encoders |
I don't really have much of an opinion about future directions for the library, as I don't use it at all now. 😉 If I'm writing a pure decoder rather than using my I think it's a shame But that's just, like, my opinion, man. I know it's far from universally shared. |
seems like @garyb is not against :-) As a sidenote: I agree that I tried to store instead of yes, I could store there not a maybe it makes sense to do the same for https://github.com/garyb/purescript-codec-argonaut as in this pr, i.e. extract decoder implementations to the one module, extract encoders to the other module and join them again together in |
@srghma I’m also primarily a user of codec-argonaut these days :) but I still want to be careful with breaking changes here that will require users to update their code. For that reason I’m happy to move decoders / encoders to their own modules that get imported to the class. And I’m not completely against changing the error type after that (but I’d like to propose it on Discourse, perhaps, so that more active users of the library have a chance to weigh in). |
Just to clarify, that’s also what I meant earlier:
Can you either update this PR or make a new one that only moves the decoder and encoder implementations, but doesn’t also make the typed errors change? |
very good 👍 there are anyway will be breaking changes to the libraries with new purescript PolyKinds) |
yes, I understood from the first time, will do when I have time) |
…mplementation to Implementation module
…mplementation to Implementation module
7e57801
to
3c5c44b
Compare
@thomashoneyman done |
<<< (traverse decoder <=< (lmap ("JSON Array" <> _) <<< rmap (\x -> NEA.cons' x.head x.tail) <<< note " is empty" <<< Arr.uncons) <=< decodeJArray) | ||
|
||
decodeNonEmpty_List :: ∀ a . Decoder a -> Decoder (NonEmpty List a) | ||
decodeNonEmpty_List decoder = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to use a single decodeNonEmpty
which can be used with NonEmpty List
as well as NonEmpty Array
, in which case we can support a decodeNonEmpty
function -- thus removing decodeNonEmpty_Array
and decodeNonEmpty_List
from this module?
We'd then use it to implement both the NonEmpty List
and NonEmpty Array
instances in the Class
module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make array a functor? But they also have different error message
import Data.Tuple (Tuple(..)) | ||
import Foreign.Object as FO | ||
|
||
type Decoder a = Json -> Either String a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm on the fence about introducing a type synonym for Json -> Either String a
; I personally prefer to introduce type synonyms only when they significantly aid readability. It's not clear seeing Decoder a
that it's a function, and so I would need to look up the type synonym to see what it is. I don't think the readability argument is that strong in this case.
That said, I know that my preference isn't necessarily shared. Elm uses the Decoder
type, for example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DecoderFunction? It prettifies implementation module a lot
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we use type synonyms then Encoder
and Decoder
are good names. I only commented because we haven't used synonyms before, using just the actual type Json -> Either String a
, and in I often prefer seeing the actual type to a synonym.
That said, these synonyms are pretty clear and they do make things prettier. For the time being lets keep the change in here, as I wouldn't mind it making it in to master.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW I strongly agree with @thomashoneyman. In my experience, obscuring a function signature via a type synonym does more harm than good. Json -> Either String a
is hardly more verbose than Decoder a
, and it's 100% clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea I also agree with Dave and Thomas. I think type synonyms (when used to improve readability) are most useful when they hide the "noise" of a type signature. I don't find the type Json -> Either String a
to be a noisy. All of that info is vital to understanding the functions inputs and outputs (And the type signature is relatively short in general)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, don't agree
I imagine there are functions everywhere in this file https://github.com/purescript-contrib/purescript-argonaut-codecs/blob/f006470fde11f39d5b17f2f40d05e6af320d6471/src/Data/Argonaut/Decode/Decoders.purs
@garyb writes JsonCodec
everywhere, not BasicCodec (Either JsonDecodeError) J.Json
Another pro argument - will be easier to change error type from String
to typed error, for us and for users
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@srghma Would you mind making the synonym change in a separate PR so it can be discussed separately? That way I can merge this PR as the other changes are good to go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BasicCodec
is already 2 levels deep of synonym too 😄.
But those codec types aren't on the same level as Json -> Either String a
, I would be fine with that as-is. They're more like the lens synonyms. I think F
in Foreign
is a similar case, and a mistake also, as again the underlying types are pretty simple without the synonym.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example with F
is good, ok, maybe I'm wrong, will revert
@thomashoneyman no need, I have changed my mind
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thomashoneyman done
encodeJsonUnit :: Encoder Unit | ||
encodeJsonUnit = const jsonNull | ||
|
||
encodeJsonJBoolean :: Encoder Boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recognize that the instance was called JBoolean
, but I think we should drop the J
prefix and just use Boolean
for this function, as well as for Number
, String
, and so on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
encodeJsonNonEmptyArray encoder = encodeJsonArray encoder <<< NEA.toArray | ||
|
||
encodeJsonNonEmpty_List :: forall a . (Encoder a) -> Encoder (NonEmpty List a) | ||
encodeJsonNonEmpty_List encoder (NonEmpty h t) = encodeJsonList encoder (h : t) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar comment here about seeing if we can just export a single encodeNonEmpty
function -- the encodeJsonNonEmpty_List
isn't a usual PureScript function name and it's unfortunate we have both NonEmptyList
and NonEmpty List
cases to cover.
encodeIdentity :: forall a . Encoder a -> Encoder (Identity a) | ||
encodeIdentity encoder (Identity a) = encoder a | ||
|
||
encodeJsonMaybe :: forall a . Encoder a -> Encoder (Maybe a) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can drop the Json
and name these encodeMaybe
, encodeTuple
, and so on, rather than encodeJsonMaybe
, encodeJsonTuple
, and so on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/Data/Argonaut/Encode.purs
Outdated
@@ -1,10 +1,11 @@ | |||
module Data.Argonaut.Encode | |||
( module Data.Argonaut.Encode.Class | |||
, module Data.Argonaut.Encode.Combinators | |||
, module Data.Argonaut.Encode.Implementation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implementation
to me sounds like an internal module that you wouldn't necessarily import into your code. What do you think of renaming the Implementation
modules to be Encoders
and Decoders
instead?
module Data.Argonaut.Encode
( ...
, module Data.Argonaut.Encode.Encoders
)
module Data.Argonaut.Decode
( ...
, module Data.Argonaut.Decode.Decoders
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
…on function as it is done for decoders
tests should work if restarted |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 I'll let this sit for another day or two in case anyone else has comments, but it looks good to me and thank you for the contribution!
What does this pull request do?
I need these functions that are not dependent on class in one of my projects
I cannot use https://github.com/garyb/purescript-codec-argonaut/ because I need only decoder part and encoder part doesnt allow to make my datatype a functor
includes:
#73
#72