2021-07-29 –, Blue
PrettyPrinting is a library for formatting composite data structures. PrettyPrinting optimizes the layout of the data to make it fit the screen width.
Out of the box, PrettyPrinting can format Julia code and standard Julia containers. It can be easily extended to format custom data types.
If you use Julia REPL to work with JSON or other nested data structures, you may find the way the data is displayed unsatisfactory. If this is the case, consider using PrettyPrinting. Compare:
julia> data = JSON.parsefile("patient-example.json") Dict{String, Any} with 14 entries: "active" => true "managingOrganization" => Dict{String, Any}("reference"=>"Organization/1") "address" => Any[Dict{String, Any}("line"=>Any["534 Erewhon St"], "dis… "name" => Any[Dict{String, Any}("family"=>"Chalmers", "given"=>Any[… "id" => "example" "birthDate" => "1974-12-25" ⋮
julia> using PrettyPrinting julia> pprint(data) Dict( "active" => true, "managingOrganization" => Dict("reference" => "Organization/1"), "address" => [Dict("line" => ["534 Erewhon St"], "district" => "Rainbow", "use" => "home", "postalCode" => "3999", "city" => "PleasantVille", "period" => Dict("start" => "1974-12-25"), "text" => "534 Erewhon St PeasantVille, Rainbow, Vic 3999", "type" => "both", "state" => "Vic")], "name" => [Dict("family" => "Chalmers", "given" => ["Peter", "James"], "use" => "official"), Dict("given" => ["Jim"], "use" => "usual"), Dict("family" => "Windsor", "given" => ["Peter", "James"], "use" => "maiden", "period" => Dict("end" => "2002"))], "id" => "example", "birthDate" => "1974-12-25", ⋮
PrettyPrinting optimizes the layout of the data to make it fit the screen width. It knows how to format tuples, named tuples, vectors, sets, and dictionaries.
PrettyPrinting can also serialize Expr
nodes as Julia code. It supports a fair subset of Julia syntax including top-level declarations, statements, and expressions.
The ability of PrettyPrinting to format Expr
nodes makes it easy to extend pprint()
to user-defined data types. Indeed, it is customary to display a Julia object as a valid Julia expression that constructs the object. This could be done by converting the object to Expr
and having pprint()
format
it.
For example, let us define a type MyNode
modeled after the standard Expr
type.
julia> struct MyNode head args MyNode(head, args...) = new(head, args) end
The default implementation of show()
is not aware of the custom constructor. Moreover, it dumps the whole object in a single line, making it difficult to read.
julia> tree = MyNode("1", MyNode("1.1", MyNode("1.1.1"), MyNode("1.1.2"), MyNode("1.1.3")), MyNode("1.2", MyNode("1.2.1"), MyNode("1.2.2"), MyNode("1.2.3"))) MyNode("1", (MyNode("1.1", (MyNode("1.1.1", ()), MyNode("1.1.2", ()), MyNode("1.1.3", …
We implement function quoteof(::MyNode)
to convert MyNode
to Expr
. We can also override the default implementation of show()
to make it use pprint()
.
julia> PrettyPrinting.quoteof(n::MyNode) = :(MyNode($(quoteof(n.head)), $((quoteof(arg) for arg in n.args)...))) julia> Base.show(io::IO, ::MIME"text/plain", n::MyNode) = pprint(io, n)
Now the output is correct Julia code that fits the screen width.
julia> tree MyNode("1", MyNode("1.1", MyNode("1.1.1"), MyNode("1.1.2"), MyNode("1.1.3")), MyNode("1.2", MyNode("1.2.1"), MyNode("1.2.2"), MyNode("1.2.3")))
Internally, PrettyPrinting represents all potential layouts of a data structure in the form of a layout expression assembled from atomic layouts, vertical and horizontal composition, and the choice operator. The layout cost function estimates how well the layout fits the screen dimensions. The algorithm for finding the optimal layout is a clever application of dynamic programming, which is described in Phillip Yelland, A New Approach to Optimal Code Formatting, 2016.
The author of PyYAML, LibYAML, HTSQL, and DataKnots.