FWIW you can do a better job with the JSON structure than in the article:

    {"GreaterOf": [
        {"Value": [0, "Dollar"]},
        {"Subtract": [
            {"Dependency": ["/totalTentativeTax"]},
            {"Dependency": ["/totalNonRefundableCredits"]}
        ]}
    ]}
Basically, a node is an object with one entry, whose key is the type and whose value is an array. It's a rather S-expressiony approach. if you really don't like using arrays for all the contents, you could always use more normal values at the leaves:

    {"GreaterOf": [
        {"Value": {"value": 0, "kind": "Dollar"}},
        {"Subtract": {
            "minuend": {"Dependency": "/totalTentativeTax"},
            "subtrahend": {"Dependency": "/totalNonRefundableCredits"}
        }}
    ]}
It has the nice property that you're always guaranteed to see the type before any of the contents, even if object keys get reordered, so you can do streaming decoding without having to buffer arbitrary amounts of JSON. Probably not important when parsing a tax code, but can be useful for big datasets.

Agreed. Any language that wants to use the fact graph is going to have to “interpret” the chosen DSL anyways, and JSON is more ubiquitous and far simpler to parse than XML. Also way cheaper in the sense that the article uses it (how many langs can you parse and walk an XML document in off the top of your head? what about JSON?)

To see why JSON is simpler, imagine what the sum total of all code needed to parse and interpret the fact graph without any dependencies would look like.

With XML you’re carrying complex state in hash maps and comparing strings everywhere to match open/close tags. Even more complexity depending on how the DSL uses attributes, child nodes, text content.

With JSON you just need to match open/close [] {} and a few literals. Then you can skim the declarative part right off the top of the resulting AST.

It’s easy to ignore all this complexity since XML libs hide it away, and sure it will get the job done. But like others pointed out, decisions like these pile up and result in latency getting worse despite computers getting exponentially faster.

What I don't like are all the freaking quotes. I look at json and just see noise. Like if you took a screenshot and did a 2d FFT, json would have tons of high frequency content relative to a lot of other formats. I'd sooner go with clojure's EDN.

So I generated a tool to take a screenshot of text and do a 2d FFT on it so I could take my own comment literally.

I was wrong. There is seemingly more high frequency content in the xml. See [1] -- the right side is the xml.

[1] https://orbitalchicken.com/fft_formats.jpg

Eh. I doubt if human developers spend much time reading any such json files.

Using jq etc will go a long way for any routine work.

We do where I work and I hate it.

Aesthetically, I consider such JSON structures degenerate. It's akin to building a ECMAScript app where every class and structure is only allowed to have one member.

If you want tagged data, why not just pick a representation that does that?

Because (imo) the goal should be to minimize overall complexity.

Pulling in XML and all of its additional complexity just to get a (debatably) cleaner way to express tagged unions doesn’t seem like a great tradeoff.

I also don’t buy the degenerate argument. XML is arguably worse here since you have to decide between attributes, child nodes, and text content for every piece of data.

Depends on the application, I suppose. For OP's application, pulling in XML is no trouble and gives you a much better solution for typed unions.

To get better than XML, I think you're looking at something closer to a Haskell- or LISP-embedded DSL, with obvious trade-offs when it comes to developer ecosystems and interoperability.