7 ms·
First: > Elm has an incredibly powerful type system Near the end of the article: >Want to decode some JSON? Hard, especially if the JSON is heavily nested an
by ToJans 9y ago
First:
> Elm has an incredibly powerful type system
Near the end of the article:
>Want to decode some JSON? Hard, especially if the JSON is heavily nested and it must be decoded to custom types defined in your application.
IMHO the lack of typeclasses/traits is really hurting Elm. Take haskell f.e.
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
data Person = Person {
name :: Text
, age :: Int
} deriving (Generic, Show)
instance ToJSON Person
instance FromJSON Person
While I understand Evan's aversion against complexity, it makes me a bit wary about using ElmLang in production. I am currently using TypeScript, but if I would need a more powerful type system, I would probably switch to Haskell/PureScript or OCaml/BuckleScript instead.
- vim_wannabe 9y agoIn Rust you can also just make your struct deserializable, use a JSON lib to deserialize a string and get the corresponding object in a Result type. The amount of work you need to do in Elm instead is huge.
- kccqzy 9y agoThat doesn't handle custom JSON schemas at all. I don't know much about Elm but at work in Haskell we mostly write FromJSON instances manually. It's probably the same amount of code as the data type definition.
- ToJans 9y agoFor custom JSON schemas nothing tops F#'s type providers [0] IMO. [0] https://github.com/jet/JsonSchemaProvider https://github.com/jet/JsonSchemaProvider
- jlouis 9y agoThis is the way to go, if you are tied to JSON for some reason. A far better solution is to get rid of JSON if most of your stack is a typed stack and then convert to JSON as late as possible. Custom JSON which people invent as they go along is just going to present your system with pain over time.
- danidiaz 9y agoOne could use a generics library to emulate something like Go's struct field tags, which decouple "external" fields names from the actual field names. Something like this is explained from 48:50 in this talk: https://skillsmatter.com/skillscasts/10181-fun-with-sum-and-product-types https://skillsmatter.com/skillscasts/10181-fun-with-sum-and-... But perhaps it wouldn't save much code compared to custom-made parsers.
- pyrale 9y agoDo you have examples of things that don't fit the vanilla FromJSON ? From the top of my head, there's lensed things (which can easily be done once with a LensJSON typeclass), and things which use a different serialization (e.g. no "tag" field, etc) for which there is little you can do, if each of your data types has its own standard. If they do, though, you could easily define a typeclass for each source (e.g. StackoverflowJSON, HackernewsJSON, etc).
- kccqzy 9y agoWe don't do type classes for this purpose. If you have to interface with some JSON with predefined schema, we just write the instances manually. It's not that hard at all—usually it's just calling withObject with a series of lifted function applications `Constructor <$> (o .: "field1") <*> (o .: "field2")`. Remember the Parser type is a Functor/Applicative/Monad/Alternative/MonadPlus so there's a whole host of utilities for these classes that make writing such instances both simple and concise. Of course if you are doing simple things like removing the leading underscore on lenses data typed, just use TH to derive the instance, passing slightly modified `Options`. If you need to manually handle tags, here's a snippet that can help you: -- | Safely accesses a JSON object where the value at a key is text. It takes an -- object, a key, and a continuation of what to do when this key is present. -- -- Example: -- -- @ -- data D = A | B | C Int -- instance FromJSON D where -- parseJSON = withObject "D" $ \o -> -- o .:=> "tag" $ \case -- "A" -> pure A -- "B" -> pure B -- "C" -> C <$> (o .: "theInt") -- t -> fail $ "Unrecognized tag in type D: " ++ unpack t -- @ (.:=>) :: Object -> Text -> (Text -> Parser a) -> Parser a o .:=> k = \m -> o .: k >>= withText ("Object with mandatory key " <> unpack k) m
- dmjio 9y agoIf you want a powerful type system (i.e. Haskell), but the benefits of Elm, Miso is a project that implements the Elm Architecture in Haskell. It obviously has typeclasses, and can encode / decode JSON on the frontend using GHC.Generics quite well. https://github.com/dmjio/miso https://github.com/dmjio/miso
- masklinn 9y agoThere's also Purescript, which is built for the web but has many of the goodies you'd expect from Haskell.
- kahnpro 9y agoI tried out Purescript for a project and didn't think it's ready for production... Generic encoding/decoding was painful, the lack of good dependency management was painful, too many things were either missing or immature. I hope in a year or two the story will be better.
- KirinDave 9y agoPureScript is a rapidly moving target. When did you try?
- reitanqild 9y agoEh, I don't know PureScript but IMO you just added another reason why it isn't production ready. Unless they are really really good at keeping backwards compability in both language and build tools.
- KirinDave 9y agoNope, they break things all the time. Or at least, they did one major break earlier this year. "Production ready" is different from "should I use this ever at all though." Doesn't really answer the question I posed though.
- 9y ago
- justinw2 9y agoIt seems like there's no solutions for generic JSON encoding for OCaml/BuckleScript/Reason either though. I've worked on various ways to do JSON encoding in Purescript through datatype generics, but the recent RowToList machinery lets us use record types directly. I have a post and some links collected if anyone is interested: https://www.reddit.com/r/purescript/comments/6mss5o/new_in_purescript_0116_rowtolist/ https://www.reddit.com/r/purescript/comments/6mss5o/new_in_p... http://qiita.com/kimagure/items/d8a0681ae05b605c5abe http://qiita.com/kimagure/items/d8a0681ae05b605c5abe
- 3pt14159 9y agoThe only JSON encoder / decoder / manipulator that I've seen that is typed and reasonably flexible is Nim's, but even there it's still 5 times more complicated than say Ruby.
- shakna 9y agoYojson [0] provides a generic way to read JSON in OCaml. Mostly by pre-defining a type that contains any valid json value. [0] https://github.com/mjambon/yojson https://github.com/mjambon/yojson
- justinw2 9y agoRight, there are some various approaches but I've had a few OCaml users tell me there were some reasons why they weren't/couldn't be used on the front end, sadly. Would really like to see some demos otherwise though
- Rotareti 9y agoWhenever something about elm pops up, I see people complaining about this. Reminds me of people complaining about Golang missing feature X. Still both languages raising in popularity. I haven't used Elm or Golang, but I'm almost convinced that simplicity is a driving factor for their success.
- BoiledCabbage 9y agoThis is exactly it. I can't speak for Golang, but why Elm wins is its simplicity. You can go through the tutorial and know the language in two days. Seriously if you ever want a weekend project, try learning elm. Even if you don't want to use it, but just to be exposed to the ideas. You csn be writing productive code in a week. If anyone tell you Haskell (or Purescript) is less than months to be productive is not being honest about what production level productivity entails. You can learn the fundamentals in less time, but the prized significantly more complex abstractions makes ramping up significantly slower. And this is coming from someone who likes haskell and is enjoying learning the language. As someone who has used a lot of languages over the years, I really do say spend a weekend trying it out. The language has great ideas and a great philosophy. https://www.elm-tutorial.org/en/ https://www.elm-tutorial.org/en/
- Rotareti 9y agoI'm playing with the idea of starting a project in Elm for a while now. I already built my own crippled version of Elm using TypeScript, React, ImmutableJS, Recompose and Ramda... The only thing holding me back is the ecosystem around JS, say ReactNative, d3, etc.
- askAwayMan 9y agoPurescript's Argonaut lib has major performance issues that are incurred for the "powerful type system." When you only have thousands of items in an array, you end up with performance discrepancies between older browsers like IE 11 and Chrome that are unacceptable outside of a toy application.
- Ar-Curunir 9y agoOn the other hand, something like Rust has similar typeclasses, and runs blazingly fast. Serde JSON is super quick and efficient.
- KirinDave 9y ago> Purescript's Argonaut lib has major performance issues that are incurred for the "powerful type system." Can you explain what you mean here? Your explanation below suggests a runtime cost for the type system, which just isn't true. I'm aware Argonaut's approach generates slower code. The nice part of any such happenstance in PureScript is that if you do find an issue it's easy to bang out some Javascript in a foreign call to do what you need. I find outside of Slamdata, folks are keen to do this. PureScript is a very new language and is still finding ways to generate code efficiently in it's target environment.
- fbonetti 9y agoI really wish people would stop spreading the meme that decoding JSON in Elm is "hard". Yes, Haskell allows you to automatically decode/encode datatypes, but this only works in the simplest of cases. For example, if your backend returns a JSON object with snake-cased fields, but your model has camel-cased fields, `instance ToJSON Person` won't work; you'll have to write a custom decoder. The automatic decoders/encoders in Haskell only work if the shape of your JSON perfectly matches your record definition. Writing decoders in Elm is not hard. It's manual. It's explicit. It forces you to specify what should happen if the JSON object has missing fields, incorrect types, or is otherwise malformed. There's a slight learning curve and it can be time consuming at first, but it guarantees that your application won't blow up at runtime because of some bad data. Because of this, JSON decoding is frankly one of my favorite parts about Elm. Typescript, on the other hand, offers no such guarantee. If you write a function that takes an Int and you accidentally pass it a String from a JSON response, your app will blow up and there's the nothing the compiler can do to help you. Personally, I'd rather write JSON decoders than have my app blow up because of a silly mistake.
- empath75 9y ago> Writing decoders in Elm is not hard. At some point, after enough people tell you that they can't figure out how to do something, one should admit that it is difficult.
- Skinney 9y agoOr that the documentation can be improved, or the API could be improved, or a number of other things. But really, JSON encoding/decoding in Elm boils down to specifying what the type of an object's field is. If that is difficult, interfaces and classes must be a nightmare.
- empath75 9y agoHere is what people are comparing it to, in terms of difficulty: json.loads('foo.json') I spent 3 days about 6 months ago, off and on, trying to figure out json decoding in elm, and gave up on the language entirely. It wasn't a matter of simply specifying types. The syntax is confusing the compiler isn't any help. I had very little difficulty working with anything else in Elm, so I think there is a lot of work to be done there. If there were a more painless way to do it, there are a lot of api's I'd love to write front ends for in elm.