A Category of Systems

Exploring the consequences of Systems & Cybernetics in Engineering
Author Tom Westbury License Creative Commons Licence

Cutting Class

Date 2019-02-11
Tags

Classes (or Blocks as they are known in SysML) are a use­ful and al­most un­avoid­able con­cept in UML. They are the mod­el­ling con­cept that al­lows for ob­jec­t-ori­ented in­her­i­tance in the lan­guage and its di­alects. In fact it is im­pos­si­ble to utilise in­her­i­tance as a pat­tern for reuse with­out it. How­ev­er, classes are not as cru­cial to ob­ject ori­ented de­sign as you may think. In this post I will make the case for a dif­fer­ent form of ob­ject ori­en­ta­tion which does away with classes al­to­geth­er. In the ob­jec­t-ori­ented pro­gram­ming par­a­digm, there are two main pat­terns for in­her­i­tance: clas­si­cal and pro­to­typ­al. Clas­si­cal in­her­i­tance re­quires no in­tro­duc­tion. For those who don’t know it, Pro­to­typal in­her­i­tance is a very dif­fer­ent beast.

There are no classes in pro­to­typal in­her­i­tance sys­tems, ob­jects just link to other ob­jects. Any ob­ject can in­herit from an­oth­er. This means that any ob­ject can be used as a tem­plate for an­other with­out the need for a class. If you are en­trenched in a clas­si­cal mind­set, it may help to imag­ine that each ob­ject has a “hid­den” class be­hind it that can change as its ob­ject is mod­i­fied.

One of the el­e­gant things about pro­to­typal in­her­i­tance is that it can be used to recre­ate clas­si­cal in­her­i­tance. By defin­ing an ob­ject as con­stant, you ef­fec­tively cre­ate a class. Though these ob­jects can still be used as in­puts to op­er­a­tions. A set of these con­stant ob­jects could be used to cre­ate any in­her­i­tance trees that you like. There­fore clas­si­cal in­her­i­tance can be thought of as a pat­tern within the more ab­stract pro­to­typal sys­tem.

At­tempt­ing to model pro­to­typal in­her­i­tance in a clas­si­cal way is a far messier en­deav­our. This means that the se­man­tics of UML are not suit­able for mod­el­ling many of the con­structs in pro­to­typal lan­guages such as JavaScript. Hav­ing to con­strain your so­lu­tion lan­guage to fit your mod­el­ling lan­guage is a huge no no for ab­strac­tion yet UML mod­ellers seem to tol­er­ate this fail­ing. Note that pro­to­typal in­her­i­tance is not the only hard to ex­press con­cept in UML, oth­ers are first class func­tions and gener­ics, but those are top­ics for ex­plo­ration in fu­ture ar­ti­cles. To un­der­stand why clas­si­cal in­her­i­tance is such an in­te­gral part of UML we shall look back at the pro­gram­ming lan­guages that shaped UM­l’s de­vel­op­ment.

Class strug­gle

The his­tory of all hith­erto ex­ist­ing ob­jec­t-ori­ented de­sign is the his­tory of class strug­gle Karl Marx (para­phrased)

So how come classes be­came such an in­te­gral part of in­her­i­tance in pro­gram­ming? The an­swer is com­piler op­ti­mi­sa­tion. Hav­ing a class gives the ma­chine a tem­plate telling it ex­actly how much mem­ory to al­lo­cate each time it makes a new ob­ject. This is why the class pat­tern came to promi­nence in C where there were no com­piler op­ti­mi­sa­tions for ob­ject ori­en­ta­tion. The C++ lan­guage, which orig­i­nally tran­spiled to C, in­her­ited this way of do­ing things.

In the es­say Classes Con­sid­ered Harm­ful The au­thor sug­gests that “class” is a pre­ma­ture op­ti­mi­sa­tion in the code that should be avoid­ed. In the case of mod­el­ling lan­guages though, com­piler op­ti­mi­sa­tion ar­gu­ments don’t re­ally cut it as a jus­ti­fi­ca­tion. Mod­el­ling lan­guages are of course ul­ti­mately hu­man, not ma­chine, con­sum­able. To be fair to the three ami­goes in the early UML days, clas­si­cal in­her­i­tance is a sen­si­ble choice wnen your lan­guage is be­ing used mainly to model things that will be im­ple­mented in ei­ther Java or C++.

From ex­pe­ri­ence, one of the hard­est no­tions to teach new sys­tems mod­ellers is the class/ob­ject dis­tinc­tion. Most soft­ware en­gi­neers are com­fort­able with, some­times mil­i­tantly stuck with, think­ing in the class/ob­ject way. How­ever most new sys­tems en­gi­neers are drawn from en­gi­neer­ing, physics and maths back­grouds of­ten with their only con­tact with code be­ing through C, Mat­lab or For­tran. These peo­ple of­ten find the class/ob­ject dis­tinc­tion hard to get their head around (I was def­i­nitely in this cat­e­gory to be­gin with).

An ex­am­ple of this would be not un­der­stand­ing why two SysML Blocks (Class­es) could not have their ports con­nected to­gether on an in­ter­nal block di­a­gram (struc­ture di­a­gram). It is not im­me­di­ately ob­vi­ous why we must in­stan­ti­ate classes as ob­jects be­fore us­ing them and al­though ob­ject ori­ented folk take this fact for grant­ed, pro­to­typal in­her­i­tance forces us to reeval­u­ate this “fac­t”. The class is al­most a pla­tonic ideal of the ob­jects that in­stan­ti­ate it. So what would a mod­el­ling lan­guage with­out classes change about the way we work?

The first ma­jor im­prove­ment to our work­flow that pro­to­typal in­her­i­tance pro­vides is a re­duc­tion in com­plex­ity to class heirar­chies in mod­els. We tend to think of class heirar­chies in terms of only the classes and for­get that each ob­ject on the end of it is also part of this hi­er­ar­chy. For mod­els with large num­bers of sin­gle use class­es, pro­to­typal in­her­i­tance would be a nat­ural choice as far fewer model el­e­ments would be re­quired.

UML ag­gre­ga­tion also makes more sense un­der a pro­to­typal sys­tem. Ag­gre­ga­tion is a rarer weaker form of the com­po­si­tion as­so­ci­a­tion in UML. Com­po­si­tion is well un­der­stood as if a class is com­posed of an­oth­er, it means that the first class con­tains a prop­erty typed by the sec­ond. Ag­gre­ga­tion, how­ev­er, is more con­fus­ing. an ag­gre­ga­tion as­so­ci­a­tion from one class to an­other tells us that the first class uses an ob­ject typed by the sec­ond. The most we know is that the ag­gre­gat­ing class has a “point­er” typed by the ag­gre­gate class; we re­quire more in­for­ma­tion in the in­stance model to know what’s re­ally go­ing on. In a pro­to­typal mod­el, the class model is the in­stance model and there­fore we know ex­actly which ob­ject each ob­ject is linked to.

Pro­to­typal in­her­i­tance has bonuses over clas­si­cal in­her­i­tance from a tool per­spec­tive too. Pro­to­typal in­her­i­tance is of­ten im­ple­mented us­ing del­e­ga­tion. This means that each ob­ject only records its de­vi­a­tion from its par­ent ob­ject. When ac­cess­ing a prop­erty called ‘fred’ of a pro­to­typal ob­ject, the sys­tem will fol­low the in­her­i­tance pro­to­type chain un­til it finds ‘fred’. This is very sim­i­lar to the ‘Fly­weight’ GoF pat­tern which lends it­self to ef­fi­cient use of mem­ory when build­ing large data­bases of ob­jects.

To con­clude I’ll leave you with a para­phrased story from clas­si­cal Greece. Plato was once giv­ing a lec­ture on his ideas of re­al­i­ty. He told the au­di­ence how all ob­jects in re­al­ity are mere in­stan­ti­a­tions of di­vine class­es. At that in­stant the trou­ble maker Dio­genes walked in and pointed at a cup that Plato was hold­ing. “If that’s only an in­stance of the class Cup” he in­ter­ject­ed, “Where is this di­vine class Cup?”. Pla­to, coolly replied: “Of course, the class Cup is in the uni­ver­sal source code, not ac­cess­able to us mere mor­tal­s”. Dio­genes, un­de­terred, walked up onto Pla­to’s plat­form and de­clared: “Y­our cup is emp­ty, Pla­to. Please do tell us all here where this con­cept of emp­ty­ness is”. Plato calmly con­tem­plated this for a few sec­onds and said “The lack of a con­tents to my cup is an in­stance of the null ob­ject class in the di­vine source code”. “That’s where you’re wrong” replied Dio­genes. “The true emp­ty­ness is here” he said as he tapped Pla­to’s head.

This post was in­spired by the in­her­i­tance sys­tem in JavaScript. If you want to know more,this site is a good place to start: In­her­i­tance and the pro­to­type chain.