/reftree

Automatic object tree diagrams for immutable data

Primary LanguageScalaGNU General Public License v3.0GPL-3.0

reftree — automatic object tree diagrams for immutable data

Join the chat at https://gitter.im/stanch/reftree

This project aims to provide visualizations for common functional data structures used in Scala. The visualizations are generated automatically from code, which allows to use them in an interactive fashion. To use this library you will need to have GraphViz installed (and have dot on your PATH).

For more examples see the materials for my talk “Unzipping Immutability”.

Examples

The following examples will assume these declarations:

import scala.collection.immutable._
import java.nio.file.Paths
import reftree.Diagram

def name(n: String) = Paths.get("examples", s"$n.png")

Since all the example code is actually run by tut, you can find the resulting images in the examples directory.

Lists

val list1 = List(1, 2, 3, 4, 5)
val list2 = List(-1, -2) ++ list1.drop(2)

Diagram(name("lists")).show(list1, list2)

By default the trees will be labeled with the arguments passed to plot (using sourcecode), but you can provide the labels explicitly:

val list1 = List(1, 2, 3, 4, 5)
val list2 = List(-1, -2) ++ list1.drop(2)

Diagram(name("lists2")).show(
  "positive"  list1,
  "negative"  list2
)

Queues

val queue1 = Queue(1, 2) :+ 3 :+ 4
val queue2 = (queue1 :+ 5).tail

Diagram(name("queues"), verticalSpacing = 1.2).show(queue1, queue2)

To reduce visual noise from Cons and Nil, the visualization of lists can be simplified. Note however that this option also hides structural sharing:

import reftree.ToRefTree.Simple.list

val queue1 = Queue(1, 2) :+ 3 :+ 4
val queue2 = (queue1 :+ 5).tail

Diagram(name("queues2")).show(queue1, queue2)

Vectors

 val vector = 1 +: Vector(10 to 42: _*) :+ 50

 Diagram(name("vector"), verticalSpacing = 2).show(vector)

HashSets

val set = HashSet(1L, 2L + 2L * Int.MaxValue, 3L, 4L)

Diagram(name("hashset")).show(set)

Case classes

Arbitrary case classes are supported automatically via shapeless’ Generic, as long as the types or their fields are supported.

import com.softwaremill.quicklens._

case class Street(name: String, house: Int)
case class Address(street: Street, city: String)
case class Person(address: Address, age: Int)

val person1 = Person(Address(Street("Functional Rd.", 1), "London"), 35)
val person2 = person1.modify(_.address.street.house).using(_ + 2)

Diagram(name("case-classes")).show(
  person1,
  "person next door"  person2
)

Usage

This project is intended for educational purposes and therefore is licensed under GPL 3.0.

To try it interactively:

$ sbt amm
@ show(List(1, 2, 3))
// display diagram.png with your favorite image viewer

You can depend on the library by adding these lines to your build.sbt:

resolvers ++= Seq(
  Resolver.bintrayRepo("stanch", "maven"),
  Resolver.bintrayRepo("drdozer", "maven")
)

libraryDependencies += "org.stanch" %% "reftree" % "0.3.1"