PFT Essays: Creating Models with juce::ValueTree

I spent a lot of time building juce::ValueTree models for PFT. Here’s a couple things I found to be helpful along the way:

 

Hide the ValueTree

Encapsulation is one of the first things you learn about when you study object oriented design. Hide your data and prevent consumers from breaking your invariants. Building complex models on top of juce::ValueTrees should be approached the same way for the same reasons. This not only protects the data invariant but also the type invariant.

 

In the past I’d build my models as plain juce::ValueTrees. In a raw juce::ValueTree if you want to assign a `juce::String` to a property that contains a float you can. These kinds of bugs are super irritating to figure out. Hiding your juce::ValueTrees prevents the data they hold from becoming garbage.

 

Pass Value Trees around as Value Trees

juce::ValueTrees are reference counted objects. This means that when you pass them around the shared object that the data is actually stored in remains the same. This is super convenient for passing them around when constructing your UI. It greatly simplifies data access between layers of your component hierarchy. That being said once you reach the final consumer you really should rewrap the tree to protect the invariant. I’ll typically assert in my model wrapper or listener classes to make sure I’m receiving exactly the type of tree I expect to see.

 

Pimpl your listeners

Sticking the juce::ValueTree::Listener implementation into a Pimpl class makes your model listeners a lot more useful. It means you can combine multiple model listeners without running into diamond inheritance problems.

The basic concept is:

The Pimpl class for MyModelListener translates juce::ValueTree::Listener callbacks into IMyModelListener callbacks. I usually combine the interface and the implementation in my listener classes which I’m sure is technically bad design but whatever.