Why does Julia not support JSON syntax to create a Dict?

JSON syntax for creating Dict/Array is really handy, especially in web development. It’s useful and high productivity when you copy data and paste to code from Stackoverflow, MongoDB or any JSON string.

Just curious, why do some new languages like Julia not support JSON syntax?

Do you mean like

D = Dict(
    :x => 1,
    :y => 2
)

??

2 Likes

Presumably because JSON syntax is not equivalent to Julia syntax, so the parser would have somehow be special-cased for JSON in some context, which would be a pretty weird thing to do.

If you want to write JSON, just use the JSON package:

julia> JSON.parse("""
       {"a": 1, "b": null, "c": [1, 2, 3]}""")
Dict{String,Any} with 3 entries:
  "c" => Any[1, 2, 3]
  "b" => nothing
  "a" => 1

I’m curious what languages (other than javascript) you would say do support JSON syntax? Python kind of does, although it’s only superficially similar (e.g. Python allows comments while JSON does not; JSON has null while Python has None).

15 Likes

My bad. I should ask “why not simply using curly bracket to create Dict like JavaScript”.

D = {
    x: 1,
    y: 2
}
1 Like

I think you would realize that, not many programming language (apart from obvious connection to web, such as Go) uses JSON syntax.

and also,

using JSON3
julia> a = JSON3.read("""
       {
           "x": 1,
           "y": 2
       }
       """)
JSON3.Object{Base.CodeUnits{UInt8,String},Array{UInt64,1}} with 2 entries:
  :x => 1
  :y => 2

julia> a[:x]
1

Because the Julia developers didn’t feel that dictionaries were such a special data-structure that they deserved their own special syntax. One need only skim the Julia github page to find many influential people with very strongly held, diametrically opposed visions for syntax uses. The dict thing seems to be actually one of the less controversial syntax choices made in the language.

Fortunately, julia has a quite powerful macro system, so you can whip up your own custom json-like dict syntax in a few lines:

macro dict(ex)
    @assert ex.head == :braces
    dargs = map(ex.args) do arg::Expr
        @assert arg.head == :call
        @assert arg.args[1] == :(:)
        @assert length(arg.args) == 3
        :($(arg.args[2]) => $(arg.args[3]))
    end
    esc(:(Dict($(dargs...))))
end

@dict{
    :x : 1,
    :y : 2
}

#+RESULTS:
: Dict{Symbol,Int64} with 2 entries:
:   :y => 2
:   :x => 1
@dict{
    "a" : 1,
    "b" : @dict{
        "c" : 2,
        "d" : 3
    }
}

#+RESULTS:
: Dict{String,Any} with 2 entries:
:   "b" => Dict("c"=>2,"d"=>3)
:   "a" => 1
14 Likes

X-ref: https://github.com/JuliaLang/julia/issues/8470

I think in some ways the reason for this choice is deeper. You’ll notice that the two examples you gave of this syntax are javascript and python. I think it’s not a coincidence that this is a decision that is more commonly made by slow languages than fast ones.

If you only have 1 fast datastructure you need a fast dictionary since it can semi-efficiently do everything that arrays, sets, and classes can (in python, most classes are just dicts with oop syntax). This means dicts are absolutely critical in slow languages. They are written in the fast language that the interpreter is written in, so the efficiency loss from not using a dedicated tool is made up for by the fact that you get a little bit of C powering it. In a faster language like julia (or Java or C++), a dict is just another data-structure. As such, fast languages tend to not give dictionaries special syntax.

4 Likes

Using JSON parser is not ideal. It lacks compile-time check for syntaxes and adds unnecessary runtime parsing to slow down the app.

Data Scientists focus on how to deal with Data Frames, but Web Developers focus on how to deal with Data Structures. JSON is almost standard on web.

Using Dict() syntax to create a dictionary is lower productivity and lower readability for complex data structures. Just imagine how to write Dictionaries in Dictionaries in Dictionaries…

Machines are getting cheaper and manpower is getting more expensive. In business world, especially for startups, the cost of development and maintenance is more important in most cases. Productive should be over performance.

If Julia is greedy enough, it should not only focus on the application of data science. One day, we might need clients and servers for training AI.

That’ my thought.

Not true. String macros operate at compile time.
Also, json is no where near as expressive as dict and you’ll have to pay a higher price from the abstract type.

5 Likes

Precisely, which is why you should just store your data in a JSON file and read it in with one of the libraries. Storing large, complex nested Dicts in code (as opposed to data) may make little sense anyway — putting large, complex, nontrivial data in code is bad practice.

I am sorry but I don’t understand what this means, or how it relates to JSON syntax.

9 Likes

Also, since it wasn’t mentioned in this topic: named tuples are another solution in Julia:

(a = 1, b = 2, c = 1:3, d = (e = 'Γ', f =  5.0))
7 Likes

I thought we’re talking about convenient copy pasta action here, if you’re serious about the data you would have it in a .json file anyways.

if you’re just copy pasting, you’re probably using some REPL, it’s not like you can copy 1GB of JSON anyways (if you’re, you’re doing it wrong), the performance change is unnoticeable considering your fingers on keyboard and mouse time.

also, compile time or not, how can you validate a JSON string without parsing it?

3 Likes

also, compile time or not, how can you validate a JSON string without parsing it?

Exactly :wink: This reminds me of this nice blog post: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/

4 Likes

I hear people say this a lot, but I’ve never seen any data to support this claim. Presumably you’d need concrete compensation package information as well as concrete server costs to build this case, but neither of those are broadly publicized in my experience.

5 Likes

On Julia 1.5, you can use the SafeREPL package to have this syntax available at the REPL (there is also a macro for source code, but I would discourage that). I have the following setting in my “startup.jl” file, to input sets and dicts as in Python, except that = is used instead of : for dicts (because : is already used for ranges; but you could modify this snippet if you really want to use :):

julia> function make_setdict(ex)
    if all(x -> Meta.isexpr(x, :(=), 2), ex.args)
        Expr(:call, :Dict, [Expr(:call, :(=>), x.args[1], x.args[2]) for x in ex.args]...)
    else
        Expr(:call, :Set, Expr(:vect, ex.args...))
    end
end;

julia> swapliterals!(:braces => make_setdict)

julia> {1, 2, 3}
Set{Int64} with 3 elements:
  2
  3
  1

julia> {1 = 2, 3 = { "a" = 4, :b = 5}}
Dict{Int64,Any} with 2 entries:
  3 => Dict{Any,Int64}(:b=>5,"a"=>4)
  1 => 2

But note that the “braces” syntax is reserved by Julia for probable future use.

5 Likes

The blog post you linked is interesting, but I think it makes a mistake when it says that this is a property of a static type system. All of those things work fine in Julia, scheme, Common Lisp or Python, where the objects are dynamically typed.

A lot of what is being described there is really just functional vs imperative style: take in a thing, and return a new value rather than take in a thing and make sure we throw an error if it’s borken.

One of the great things about Julia, as highlighted above, is that if you want curly brackets to construct dicts, you can write a package to do that and it will be just as “first class” as if it were part of Base Julia.

So the answer to your question:

I should ask “why not simply using curly bracket to create Dict like JavaScript”.

is, “You can” :slight_smile:

5 Likes

Just my two cents…

I wrote a small package to support Javascript Literals, JSObjectLiteral, so that you can write in Julia:

e = "ee"
a = @js { 
  b: 10,
  c: [ 20, { d: "thirty", e } ]
}

which is almost like you can in javascript—it is just the string literals that have to be double-quoted instead of the more common single-quoted string in javascript.

This started out as an exercise for me trying to understand Julia macros. The package can do more tricks, like assign into a dict @js { a, b } = dict, and has a type JSObject to make deep object traversal more easy to write, like a.c.e = "fifty".

12 Likes

How big effort it would be to support javascript syntax? I don’t need the feature, I am just interested in how macros work.