User’s Guide, Chapter 36: Clients and Weak References¶
(This Chapter is a work in progress)
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.
Note
s 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
Note
s and Stream
s. 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##>
Or similarly for a derivation:
n2 = n.transpose('m3')
n2
<music21.note.Note A#>
n2.derivation.origin
<music21.note.Note F##>
n2.derivation.client
<music21.note.Note A#>
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
:
n2.derivation._client
<weakref at 0x115623790; to 'Note' at 0x1155f0dd0>
n2.derivation.client is n2
True Note: Any feature beginning with an underscore may change inmusic21
without notice – these are the things that the developers reserve for changing their own implementation methods at any time. In fact, in an earlier version of this guide (and ofmusic21
),.duration.client
had a private.duration._client
feature which was a weak reference. As Python has become more sophisticated with its “garbage collection”, this hiding of client became unnecessary, so it was changed without an announcement. For reasons to be explained below,.derivation._client
is unlikely to go away anytime soon.