Object Prototyping:
Filter:
Guides | Guides

Object Prototyping

Writing runtime 'classes'

You cannot create nor edit a class without recompiling the language... but what if you need that?

Object prototyping is a middle ground that lets you build class–like structures at runtime. It works by taking advantage of the class IdentityDictionary (often the subclass Event is used) and the special method Object: -doesNotUnderstand. While there are some oddities with this approach, it is extremely powerful.

Instance Variables (Members)

Instance variable–like things can be created by just adding keys to an IdentityDictionary

Unlike normal classes, you can create new instance variables at runtime.

Methods

By assigning a function to a key, you can call that function as if it were a normal instance method.

However, the IdentityDictionary is passed into the function as the first argument. Usually, we call this argument self as it performs a similar role to the keyword this.

Functions: Variable Arguments also work.

Constructors

There is no direct way to mimic a constructor, but this isn't a problem, as we can simply make a function that returns the IdentityDictionary.

Private Instance Variables (Members)

These can be implemented inside the constructor function as normal variables, however, you don't add them to the dictionary.

Dangers

There are two drawbacks over classes.

The first, is that any key, including 'methods', can be overridden at any time. Essentially, what makes IdentityDictionary powerful, also makes it fragile and easy to break. The only way to avoid this mistake is by being vigilant when adding keys to an object prototype.

The second drawback is that you cannot have a key with the same name as a method in Event or any parent class, otherwise the real class's method will be called, not the pseudo–method you have written.

As seen above, one expects the value 10 to be returned, but instead Object: -numChannels is called and the value 1 returned.

There are two ways to mitigate this. One, use longer keys or names in snake case rather than pascal case: that is names_written_like_this, ratherThanNamesWrittenLikeThis, as SuperCollider only uses the latter.

Two, assign outside of the brackets, where a warning will be generated.

Inheritance

This is implemented with IdentityDictionary: -'parent' and 'proto' variables. Technically, this can be used to do more than inheritance, but only inheritance is shown here.

This is done by assigning the parent to another dictionary to lookup keys in.

This is similar to how Javascript and other prototyping languages work.