1. 17

    There are only two real deficiencies with JSON, IMHO:

    • No standardized method of commenting
    • No multiline strings

    There are other problems, of course: no standardized date format, no standardized mechanism for including arbitrary binary data, no hexadecimal notation, etc….but really the two things mentioned above are the only true problems it has.

    (Again, IMHO.)

    1. 36

      I would argue failure to support a trailing comma is a serious defect in any format expected to support the addition of elements over time.

      To clarify, that’s maybe not a defect in json per se. If it’s just a serialization format, fine, whatever. But for the use case of tracking dependencies, configurations, etc., it’s bad. Choosing to use json for this is a defect.

      1. 7

        EDN’s use of whitespace as element seperators, is better than commas. https://learnxinyminutes.com/docs/edn/

        1. 6

          I heard an anecdote from someone who had to make a streaming json parser, and its performance was significantly hampered because it had to check for the trailing comma.

          1. 2

            I have a “counter-dote”. https://github.com/stig/json-framework/blob/master/Classes/SBJson5StreamParserState.m implements a state machine for a streaming JSON parser that is not impaired at all by checking for trailing commas.

            Admittedly I remember struggling with handling the trailing comma issue previous versions, before I adopted the state machine. Also, my parser is not the most performant—even for Objective-C.

          2. 2

            Lack of trailing commas is also one of the things that irks me most about SQL…

            1. 5

              haha, so I was even going to suggest sql as an alternative to json for configs. Create an in memory sqlite database, then .load and .dump. What could be better than the ability to query your config? And it plays nice with version control because every line ends with a semicolon, not just some of them.

              PRAGMA foreign_keys=OFF;
              BEGIN TRANSACTION;
              CREATE TABLE depends (name, version);
              INSERT INTO depends VALUES('foo',7);
              INSERT INTO depends VALUES('bar',3);
              COMMIT;
              

              Plus you get atomic updates, rollback, etc. when doing a hot reload. Awesome, right? :)

              1. 5

                Yeah but as someone who deals with code or system configs first, and databases as an afterthought, SQL just seems so flimsy. Database setup is imperative more than declarative. Data insertion is the same. And the actual data types are terribly weak unless you go through a lot of work trying to enforce invariants.

                I do know a lot of this is my own bias, because there seems a fairly large cognitive gap between “functional programming first” programmers such as myself where functions and structures come first and composing them should be easy, and “database-first” DBAs like some of my friends where sets of structures come first, functions seem a special case, and composition seems to have different rules… But it’s a hard gap for me to cross.

                1. 4

                  And the actual data types are terribly weak unless you go through a lot of work trying to enforce invariants.

                  This is one point that I disagree with. If you’re primarily working with MySQL or SQLite, I guess it may be true, or if you’re thinking about SQL databases as filtered through a “least common denominator” database library, but types are pretty robust in most databases.

                  1. 2

                    SQL Server/TSQL is also strongly typed.

                    1. 1

                      Yeah, it’s things like that which find me always reaching for postgres over MySQL. <3

                      As I said, part of the problem is mine… I’m not actually very good with databases and so I tend to solve everything the most complicated and brute-force way. I’m trying to improve though, bit by bit.

                    2. 1

                      If you haven’t read The Third Manifesto you should. Made me fall in love with the relational model all over again

                    3. 1

                      Kinda like what slapd does, but I must say I’m not very fond of configuring it that way.

                2. 15

                  Also it doesn’t let you round trip numbers correctly.

                  EDIT: To elaborate, you can’t store +/-Inf or Nan to them.

                  1. 6

                    This shortcoming is so important when you deal with complex number crushing applications that many libs add them, for example Google’s Gson. I even made a library to parse those numbers client-side (JSON.parseMore, this approach having the disadvantage that it isn’t as heavily optimized as the native JSON.parse of the most modern browsers, which is also, btw, why you can’t easily replace JSON by other formats like messagepack which would otherwise be faster to parse).

                    1. 2

                      With regards to parsing performance, an interesting approach is to piggyback on those highly optimized parsers. For example, the Transit format provides a richer set of builtin types and an extension mechanism (pretty much equivalent to EDN) but is encoded as JSON or MsgPack while in transit (I guess that’s the reason for the name). That way, serialization and deserialization profit from the host format’s optimized parser implementations.

                      1. 1

                        Transit is just a hack to enable use of native-code JSON parser for browser applications, because parsing EDN might be too slow with parser written in js.

                        It’s not even human-readable and of course is absolutely unusable for configs. We’re using it for React Native and I have to convert it to EDN every time I want to debug some output :(

                  2. 9

                    JSON5 addresses a lot of these issues.

                    1. 6

                      Ren has literals for most common types (dates, IP addresses, URLs, emails) built-in.

                      Another interesting approach, that is far more powerful (while still keeping it sane) is Dhall.

                      1. 2

                        Ren looks a lottle like REBOL, which is neat to me.

                        Dhall looks cool.

                        1. 6

                          Ren looks a lottle like REBOL, which is neat to me.

                          Oh, well, because it is to REBOL what JSON is to JavaScript :)

                          Dhall looks cool.

                          I’ve never personally used it extensively but I’ve heard people using it to also handle configuration updates (e.g. a Dhall function changing old config into new config) that are type-checked. Dhall functions are powerful but without Turing-completeness. In other words JSON and TOML are just variations on syntax preferences but ultimately they’re like each other, Dhall is something else.

                        2. 1

                          Dhall allow external url which looks like crazy from security standpoint

                          1. 1

                            Yep, but you can add content digest to the URL (SHA sum).

                            1. 1

                              it is not by default, as such will not be always used and eventually become a security hole

                        3. 4

                          I do like hjson as an alternative to json nowadays. When I used toml with Cargo/rust, It seriously cost me some time to understand what “data structure” the toml file would be parsed into. I guess I still don’t firmly understand it.

                          1. 1
                            • No streaming capability
                            • No efficient encoding
                            • Requires quotes escaping in strings (and consequently to parse every byte in every string to find a terminator)
                            • No ability to skip ahead during decoding
                            • No ability to store raw data

                            People invented TLV for a reason https://en.wikipedia.org/wiki/Type-length-value

                            ASN.1 DER: https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One#Example

                            1. 1

                              Since others have mentioned some alternatives, there’s always Lua. I use Lua as a configuration file format both for personal projects and for work. Comments, multi-line strings, ability to call functions (like the example one calling os.setlocale()) and trailing commas. Oh, don’t like commas? Replace them with semicolons if you wish.