User’s Guide, Chapter 36: Clients and Weak References

This chapter explains some of the underlying aspects of music21‘s functioning that may be helpful for someone doing advanced work in understanding how the system works.

It pays to have good references

I’ve mentioned several times indirectly or directly the concept of references in music21 and it’s worth mentioning a bit what they are. (Programmers with a lot of past experience outside music21 can skim or skip ahead)

A reference is a relationship between two objects that allow them to share information with each other on a short or longer term basis. There are several types. Let me give an analogy that might help separate them.

Suppose two people (let’s call them Jane and José – the names of two students who worked on music21) meet at a conference mixer and discover they have a lot in common (“You like computer music analysis too?!”). They can chat about whatever they want at the mixer but after they leave, they have no way to communicate with each other. We’ll call that being in the same scope (the mixer) but having no reference.

On the other hand, say José and Jane exchange phone numbers and emails – now they’re able to ask each other anything at any time from here on out. I’ll call this having a normal reference (also called a hard reference) to each other.

Imagine a third scenario where they exchange their hotel phone numbers (okay, unrealistic in 2015, but bear with me). Now they can chat about anything for a limited amount of time, but if Jane comes back in a month and dials room 348, odds are, she won’t find José there (my travel budget isn’t that big). Maybe they figure it’s unlikely that they’ll be in the same place again. Or sometimes it’s good to have single-serving friends. In computer speak, they have weak references to each other.

It’s also possible that the references can be asymmetrical. Jane could have José’s permanent phone number, but José might only have Jane’s room number. In this case Jane has a hard reference to José but José only has a weak reference to Jane.

Most items in music21 have no reference to each other; they can only share information when we put them in the same scope (the mixer) and introduce them to each other (e.g., statements such as if x > y:).

On the other hand, some objects have hard references to other objects. For instance, each Note object has a hard reference to a Pitch object. Any note can get its pitch through the .pitch attribute. But Pitch objects do not have hard references to their Note objects. If you have a Pitch there’s no .note attribute that lets it find its own Note.

This seems like a design flaw, and in an ideal world, they would have references to each other. Sometimes you have a variable, such as p, which is a Pitch and it’d be great to do p.note to figure out what Note it belongs to. But there’s a general rule in designing programs that’s worth following: it’s dangerous for two objects to have references to each other. Why? Because each object takes up space in the computer’s memory. At a certain point, operating systems need to free up objects that no one is using any more (like when you close a program, all that undo data tends to vanish). Operating systems know when an object is no longer being used when there are no (hard) references to it. If p had a .note attribute pointing to n and n had a .pitch attribute pointing to p then they would never get deleted even if they were no longer in use (this process is called “garbage collecting”).

One way to get around this problem is through the use of weak references. A weak reference, like someone’s room number, lets a object communicate with another for a certain length of time, but not forever. For a computer system, if object1 has a weak reference to object2, it says that object1 would like to communicate with object2 as long as possible, but that this relationship isn’t strong enough to prevent object2 from disappearing when nothing else needs it.

Notes and other objects have strong references to their Duration objects, stored in the .duration attribute, but Duration objects only have weak references to their Note objects. This makes sense: as long as the Note exists, the Duration had better be around, but once the Note disappears, there’s no need to keep its Duration.

Some objects that are in a weak reference relationship to others include Notes and Streams. Streams have hard references to their notes – they can’t just have their notes disappearing unannounced! But Notes only have weak references to the Streams that they are in.

There are many notes in a stream, but there’s only one duration on a note. When there is a one-to-one relationship between two objects, the object holding the hard reference is called, in music21, the “client.” Thus in a Note/Duration relationship, the Note is the client of the Duration. The relationship name implies that the Duration is there to serve the client, the Note. When there’s no client, the Duration is off duty and can go home.

Weak references can be a bit of a pain to work with in Python compared to some other languages such as Perl (but much easier than, say, Javascript, where they are only beginning to exist). Thus music21 as much as possible tries to hide its weak references. We hide things by making their attributes begin with an underscore _, which makes them not appear in the docs. For instance, if we create a Note and look at its .duration.client it looks like the Note itself:

from music21 import *
n = note.Note("F##2")
n.duration.client
 <music21.note.Note F##>

But actually .client is not an attribute or reference at all, but a property: a small method that is run invisibily without needing () marks that converts a weakref into a normal object. The actual weakref is stored at ._client:

n.duration._client
 <weakref at 0x107967318; to 'Note' at 0x10798b630>

We have already seen the use of weak references to store clients in the Derivation method:

n.derivation.client
 <music21.note.Note F##>
n.derivation.client is n
 True