We will begin our journey through the graphics kernel of Pharo, by focusing on Color, one of the building blocks of computer graphics.
Let’s start by reading the class definition of a color in Pharo (Version 30356):
In Color there are too many class Vars referencing named colors, thus we will attempt to reduce the high number of class variables, or at least provide a good reason that explains the complexity of the class.
Color defines 32 class variables which reference the set of named colors, used throughout the system, such as Black, Blue, Brown, Cyan, DarkGray, and LightYellow.
The current design is neither flexible nor modular because:
- to register a named color one must add a class var to Color, and a corresponding accessor.
- the default set of named colours is fixed in the method #initializeNames.
Besides, the current implementation of registering a named colour is cumbersome, because it uses meta-programming to add the class var and accessor. See the following method in Color which is responsible for initializing and registering the default colors in the image:
We propose a simpler implementation of named colors, by adding to the Color class a registry of named colors, with both methods for registering a new named color and accessing them. The registry is initialized to the same set of default colours, but easily extendable without resolving to meta-programming.
The fix removes all the class variables representing a named colour, and provides accessors for the default ones for backward compatibility, (i.e.: Color class>>black,etc..), which results in a simpler class definition:
Moreover, the fix introduces an optimisation for answering the name of any registered color, in the form a instance variable in Color. Currently, a registered color name is found by testing an instance for equality against the registered colors (ColorNames class var of Color).
The Performance Penalty
We measured the performance penalty of an extra message send when asking for a registered color. Currently, retrieving a registered color is achieved by simply accessing a class variable.
Instead, our fix involves accessing the registry. See the following convenience methods for accessing the default colors, and the more general method for any registered color.
I implemented a class that imports the fix, and tests that the new color registry holds identical colors for each named color, before and after loading the changes, and informs the time to run the same benchmark. To load, test and benchmark place the change set with the fix in the same directory as the image, then load the NamedColorBenchmark class and evaluate the following.
The benchmark shows that for an extreme case which asks 100000 times for every named color, the performance penalty of a color registry, compared to having numerous class variables referencing every named colors, is 300%.
The latter might appear as a penalty far too great to pay for the sake of a simpler and modular graphics infrastructure, but since the benchmark tests a worst case scenario, having an extra message send to access the registry of named colors, won’t be such a burden for the normal case.
If a certain application can do without a super fast named color accessing, it can implement it’s own cache using as many class variables as needed for the required colors, instead of overcrowding the Color class.
I’ve submitted the code to Issue 11433 in the Pharo bug tracker
There you can find the change sets of both the fix, and the benchmark.
In the next post, we will challenge the existence of both Color and TranslucentColor in Pharo, with the purpose of unifying both concepts into the same class.