OOP Shower Thoughts: Private, final, etc.

Following this proud tradition of posting brain-dumps, this post is – and the ideas contained within are – somewhat of a work-in-progress and subject to change.

There’s an adage one may encounter in the OOP world:

Make everything private unless you have a specific reason not to.

Some purists will even go one step further and insist that the same rule applies to the final keyword i.e. all methods and classes should be final without some specific reason for them to not be.

Personally, I haven’t (voluntarily) used the private or final keywords in 8+ years.

I have encountered two main motivators behind the “everything private” philosophy; below I’ll outline why I disagree with both of them.

1. API design & protecting developers from themselves

I’ve been there myself, in the early days of my programming career. You’re creating some base class which provides some kind of service/behaviour that is intended to be “consumed” via inheritance. Consequently, you find yourself thinking things like: When other developers inherit from this class, how do I stop them breaking things? How do I ensure they call the parent constructor? etc.

I would suggest that this line of thinking – whilst understandable – is flawed from the beginning.

Taking a step back to look at the “philosophies” underlying inheritance & API design in general:

In a world where people have things that they need to log, I might create some Logger class which – as the name might suggest – logs. In 2022, it would be proper of me to create some LoggerInterface – which is essentially my way of saying to my end users: “Regardless of what I do to the internals of this class in future versions, you can always call these methods and things will work. I guarantee it.”

The end user need not be bothered with the internals. They don’t need (or probably want) to care about how a logger, logs; they just want to log stuff. I’ll call this the “don’t bother me with the details” approach.

The rules change somewhat over on the inheritance side of the fence. Specifically, the expectations of what is within an end user’s domain of 1) knowledge and 2) responsibilities.

Let’s say I instead created some AbstractLogger class. This is not itself a complete and functional logger, but it offers some of the scaffolding another developer – the target audience in this scenario – might be able to use to implement their own logger. Here we encounter the question: What kind of contract am I entering into?

I think this is where people find themselves sandwiched between two worlds; they want to offer a “black box” that can be used without being understood – the don’t bother me with the details philosophy. However, this is – I would argue – antithetical to the very paradigm of inheritance.

You may be familiar with terms like is-a and has-a. Composition is an example of a has-a relationship; some Car object may have some external Engine dependency i.e. it has-a(n) Engine. Inheritance is an example of an is-a relationship; when we say Logger extends AbstractLogger, we are saying Logger is-a AbstractLogger.

This brings us to the question of the domain of knowledge involved in each scenario. Perhaps we can ask the question: What right do I have in saying that my Logger is-a AbstractLogger, when I’m treating AbstractLogger as some black box that I do not fully understand?

Labouring the car analogy: It would be fair to say that a car manufacturer need not understand the internals of an engine; for their purposes, they need only know how to interface with the engine, to do things that need to be done. Someone wishing to modify the engine itself for their own purposes – creating some Engine 2.0 – does not have the same claim to ignorance.

In other words – and perhaps in summary: When developer 1 is creating some abstract/base class intended to be treated as a “black box” with some vaguely-defined contract (e.g. written in documentation rather than an interface) – and when developer 2 is in the market for some base class they can use without “being bored with the details” – I would put it to you that both developers have their conceptual wires crossed.

Developer 1 should either a) create some concrete class with an interface (for example) – or b) accept that their contract with their end user is one of, “I’ve done some scaffolding work for you, but knowledge of how this all works – including not breaking it – is your responsibility.”

Similarly, Developer 2 should either a) be looking for something they can use as a service/dependency, complete with an interface – or b) accept responsibility for understanding & properly using the base class.

2. Limiting the cascading effect of changes throughout the system

That is to say: If 1) you create some base class A – and then 2) subsequently, three of your colleagues independently create derived classes B, C and D – and then 3) the day comes that you need to make some breaking change to A, 4) it’s then also necessary to update B, C and D.

The private and final keywords offer a promise of avoiding this situation by preventing it from even being possible in the first place.

They also prevent two other things: code reuse and the O in SOLID.

That “code reuse” point is potentially the most significant – because in one’s efforts to prevent one type of problem, one might encourage the creation of another, much more serious problem.

If your class does 98% of what a colleague needs it to do – and said colleague could fill in that 2%-shaped hole in their heart through inheritance – but you have prevented them from doing so – then they are only left with two (realistic) options:

  1. Re-invent the wheel – in which case you now have code/logic duplication in the code base – which is possibly/arguably even more dangerous than cascading effects on derived classes.
  2. Refactor your class directly – which is another insult to the O of SOLID and increases the risk of introducing bugs, etc.

These are both also a drain on your colleague’s time – and they create an additional hoop your colleague needs to jump through before they can do whatever it is they were trying to do in the first place.

There is a slight caveat here: It’s arguably desirable that any behaviour/logic which is in such high demand for (re)use throughout the system, is available for consumption as some kind of service – and as a consequence, in an ideal world there would be no inconvenience caused by preventing inheritance and overriding and such.

The reality is that human beings are notoriously terrible at predicting the future. Making your methods private and final is perhaps akin to declaring to the world: “I have imagined every future possibility – and as a result, this class is perfectly designed and abstracted such that no one would ever find themselves wishing one of my methods just did something slightly differently.”

Any developer willing to make that declaration is certainly braver than I. They’re also almost certainly wrong.

Finally, as a general musing: I also wonder at what point a problem becomes a business-level problem – e.g. to be solved through coding standards, policies and procedures, etc. – rather than something to be solved in the design of one’s programming language or software architecture.

… Maybe?

OOP Shower Thoughts: Code reuse, inheritance, etc.

Recently I’ve spent more time than usual thinking about software architecture, OOP design and such – and figured it might be worth writing some of it down – for whatever purpose that may serve.

I have no particular structure in mind for this post – so if it is still a jumbled mess by the time I publish, please accept my apologies. All of this ties together at the end, I promise. (I hope.)

Today’s musings revolved mainly around inheritance, code reuse, contracts/interfaces and such.

As is standard in OOP discussions, let’s establish a contrived example of objects that somewhat represent real-world concepts. Let’s imagine we have some class Human – which comes with all the bells and whistles one might expect for a human being – and we’re intending to extend this base class in a shiny new Metahuman class – which has additional superpowers (obviously).

An obvious question to ask might be: Are metahumans, human? Perhaps another angle on that question is: Can humans fire lasers from their eyeballs? Intuitively, you may say no – because most can’t (as far as we know).

Humans can talk – and humans are also animals – so when asked whether animals can talk, we might say, some can – or in other words, yes. 2 billion years ago, no animals could talk – as far as we know – so what are the implications of that?*

* This is a rhetorical question.

Let’s introduce something else into the mix, along the lines of contracts & the Liskov substitution principle and such:

Let’s first flesh out our human:

class Human
{
    public eat(Substance something)
    {
        Mush mush = this.chew(something)
        this.digest(mush)
    }

    public shakeHandsWith(Handshaker person)
    {
        person.acceptHandshakeWith(this.getRightHand())
    }

    protected chew(Substance something)
    {
        // etc.
    }

    protected digest(Mush mush)
    {
        // etc.
    }

    protected getRightHand()
    {
        // etc.
    }
}

If we’re responsible, considerate, well-educated engineers, we might cobble together an interface for good measure – and feel very proud of ourselves for doing so:

interface HumanThings
{
    public eat(Substance something)
    public shakeHandsWith(Handshaker person)
}

The code and/or language isn’t important here; we’re just illustrating that humans can do things like chew & digest food – and shake hands when prompted. Usually.

I went to the effort of making that “usually” italic for a reason. Y’see, not all human beings have right hands – or left hands, for that matter. They cannot shake hands, but they are still human. Another illustration might be:

class HumanWithoutHands extends Human
{
    public shakeHandsWith(Handshaker person)
    {
        throw new ThisPersonCannotShakeHandsException
    }
}

Now we find ourselves in a situation where we have agreed that humans can shake hands – codified in a contract, even – but there exist in the world, humans who cannot shake hands. This violates all kinds of rules / laws / maxims / best practice.

As half of a solution to this academic problem, we might then reconceptualise the paradigm at play. We might say that, when we originally created our Human class, it was implied that a) our class was intended to serve people who need humans capable of shaking hands – and by extension, that b) all such humans which derive from our base class, must necessarily be hand-shaking humans.

I say this is half of a solution because it leaves at least one other problem on the table: Code reuse.

For the most part, our original Human is a perfectly serviceable implementation of a human being. The digestive system is reusable – potentially. We’re just prevented from doing so if we’re bound by the contract that only hand-shaking humans can inherit this implementation.

At this point, I wonder whether it’s better to again look at all of these concepts through a different lens:

First, we should perhaps stop seeing our Human class as a representation of what a human being is, but instead what a human being might be. At this point, we might drop the interface altogether – and make the class abstract.

Instead, we might make our contracts elsewhere:

interface HandShaking
{
    public shakeHandsWith(Handshaker person)
}

interface Feeding
{
    public eat(Substance something)
}

class HandShakingHuman extends Human implements Feeding, HandShaking
{
    // etc.
}

class OtherHuman extends Human implements Feeding
{
    // etc.
}

In other words: Separate the implementation from the intended usage (i.e. interface/contract/whatever.) Things which depend on humans capable of shaking hands, depend on the HandShaking interface, not a monolithic HumanThings interface. Derived classes can reuse the Human base (abstract) class without having to necessarily maintain its original behaviour.

… Maybe?

A quirky solution to HackerRank’s “Team Formation” problem

As a preface, I’d like to say that this article isn’t intended to help people cheat at the problem, but is posted for the intellectual exercise contained within. Hopefully the folks in and around the HackerRank community won’t mind.

Lately I’ve been having some fun with the challenges on HackerRank. By all accounts, the general (and consensual) solution/s to the Team Formation problem involve some combination of data structures, sorting algorithms and such.

That’s all well and good, but having hit my head many times as a child, something in the back of my mind was nagging away at me, insisting that there existed a more specialized solution. As is a recurring theme of this blog – and indeed my life – I could not resist its call. Fortunately, this one actually paid off.

The algorithm I subsequently developed does not (in theory) depend on any particular data structure nor require sorting; it satisfies the condition of being “greedy“; (potentially) has a time complexity of O(n), requiring only 1-2 loops; and for added lolz, can be made stable and even online if necessary.*

* While this is all possible, in some cases it’s not practical; in one particular implementation I did have to use std::sort. I’ll elaborate more on this at the end of the post.

The problem (briefly)

The objective of the Team Formation challenge is to accept a list of integers representing skill values for members of a team – and to organise those members such that a) for any one member with skill x, either that member is the lowest skilled member of the team or there exists another member of the team with the skill x-1 – and b) the members are organised into as few teams as possible, with members being spread as evenly as possible across every team. To pass the test, one must output the size (number of members) of the smallest team.

For example, given the set \{ 4, 5, 2, 3, -4, -3, -5 \}, the two teams that can be formed are \{ -5, -4, -3 \} and \{ 2, 3, 4, 5\}. The smallest team is \{ -5, -4, -3 \} and so the correct output for this test case is 3. (Note that it would be erroneous to organise this input into the teams \{ -5 \}\{ -4, -3 \} and \{ 2, 3, 4, 5\}, for example.)

Abstractions

Imagine a grid. If you’re struggling, below is a visual to help you along:

graph1

A graph, similar in style to those pioneered by William Playfair in the late 1700s.

For an example input of \{ 51, 47, 45, 46, 46, 47, 48, 47, 50, 47, 47, 49, 51 \}, the correct team formation can be visualised as:

graph2

If another value 48 were to be added, it would travel down the x axis towards 0 to the next free slot, resulting in:

graph3

This works because there is a “free” 47 at coordinates (3, 47). If this were not the case, the new value 48 would be placed at the end of the row – at (5, 48). Below is another example, using an additional value of 50.

You get the idea by now.

You get the idea by now.

Following a set of rules for how to handle various local conditions when a new member is added, it’s possible to organise and – if implemented properly – effortlessly reorganise the members into their most appropriate structure. You can even track the size of each team on the fly.

The implementation

For the same reason that I’ve not gone into the algorithm in much depth (i.e. not wanting to help out the dirty cheaters too much), I won’t post any code here. However, I did write an implementation which passed the HackerRank test cases.

Following that, I decided to grab a few of the other top scoring solutions along with some of the larger test cases and benchmark them locally against my algorithm using Very Sleepy. The numbers are listed below (lower is better):

User Average time
surwdkgo 0.494
visanr 0.275
Kostroma 0.182
Meeeeee! 0.166

As you can see, I outperformed the competition – which was a reassuring conclusion to this little experiment, having spent far more time and energy than was warranted.

Some notes about implementation

This algorithm doesn’t require use of any particular data structure or sorting algorithm; you can just use the integer value of the skill level x and perform local operations on x-1 and x+1 and such.

Under certain conditions (e.g. access to large memory or some assurance that x will be within a certain range) this means you can perform all necessary operations using a regular unsorted integer array. However, as the conditions of the challenge state that x may be as large as 10^9 – which is far too big for the test scenario – that leaves two options: use another lookup method (e.g. hash tables) or sort the array.

In my first attempt I did use an unordered_map, but lookups created a bottleneck so I tried out the sorting approach, which significantly improved performance.

Even after all of this, there’s still a voice in my head telling me that an even better algorithm exists, but… I must move on. I’ve satisfied my curiosity (mostly). And I have things to draw.

Fuck it

For a while now (and by “while” I mean 5+ years) I’ve been wanting to create a web comic. By some miracle I have taken the first step towards that goal and set up a Tumblr blog to host said strips.

For those who are interested, the URL is http://newphalls.tumblr.com/. I’ll probably also be pestering my Twitter followers with updates – so there’s the option of following me there

My intention is that the cartoons will feature a number of topics, from gaming to world events. This is all assuming I actually post anything further in the future (I will try, I promise).

/

Programming as art?

Not too long ago, admiring the craftsmanship of the Kritonios Crown got me thinking about the various ways in which people have taken a particular skill – such as painting, sculpting, smithy, writing, etc – and turned it into art.

While plenty has been said about computer programming having artistic undertones, I began to wonder whether it would be possible to create a work of art in the truest sense of the word, through the medium of code.

First, I had to define some parameters for what counts as art. The essence of “what is art” has forever been elusive and is hotly debated. However, I settled on a condensed criteria that I believe the majority of people would be happy to accept. They are:

1. Expression; purpose and meaning.
2. Evocation; provoking an emotional response.
3. Imagination; creativity and innovation.

With this, I began thinking about a way that I could turn code into art.

Expression and evocation

I knew immediately that I wanted to pay homage to the miracle of existence, life and the universe. I hoped originally to inspire in the viewer’s mind the same emotions of reverence and confusion that I feel when I look out to space or consider the intricacies of nature – and I feared that some (or indeed many) may feel nothing at all when they look at my piece. If that were the case, for those people, the art would be a failure.

But then I considered that some people do feel nothing but apathy and indifference when they look at nature (presumably in between watching reality TV shows and listening to Beyonce, but that’s just stereotyping). In its own way then, even indifference towards my art could be taken as another accurate portrayal of my chosen subject.

Ultimately, I decided to drop the expectation of provoking any one particular thought or emotion, as long as one or the other occurred at all. I embraced the subjectivity of my art, just as the meaning of existence is itself subjective.

Imagination

Having settled on what I wanted to say and how I wanted people to feel, I needed to plan the execution. I decided that I wanted to write some code which would mystify even my fellow programmers, but at the same time, I felt like obfuscation would be a cheap copout.

Even the choice of language was assigned meaning. Spoiler alert: I chose PHP because the history of PHP itself is a tale of haphazard guesswork and random mutations that may or may not be beneficial, much like biological evolution. (Not language bashing; just some innocent humour.)

The result

The end result can be seen in this Gist.

I title this piece, “Microcosm.” Recall that this code is not merely a script that has been fed through a code obfuscator; the code stands as-is – and, like the universe it hopes to represent, has mechanics and implications.

Thank you and good night. Much love.

Web development in Julia: A progress report (Warning: Contains benchmarks)

Continuing my quest to explore the idea of using Julia for web development, I wanted to address some of my own questions around performance and implementation. My two biggest concerns were:

  1. Should Julia web pages be served by a Julia HTTP server (such as HttpServer.jl) – or would it be better to have Julia work with existing software such as Apache and nginx?
  2. How would Julia perform on the web compared to the competition?

Addressing the HTTP server question

After some consideration, my personal conclusion is that a server implemented in Julia would be another codebase that would need to be maintained; would mean missing out on tools available to existing server software, such as .htaccess, modules and SDKs; and would ultimately feel like reinventing the wheel. I feel it would be more sensible to leverage existing software that already has active development and has been tried and tested in the wild.

Following from this, I knew that my primary performance concern should be the interface between the server and Julia. In my previous posts, I was using Apache and running Julia via CGI. CGI is slow enough, but a known fact of Julia is that the binary is somewhat slow to start due to internal processes/compilation. I figured that FastCGI would be the next best option – and as there are no existing solutions (except for an incomplete FastCGI library), I set about creating a FastCGI process manager for Julia.

FYI: I’ve decided to release all of my web-Julia-related code under the GitHub organisation Jaylle, which can be found at https://github.com/Jaylle. Currently only the FPM and CGI module are available, but in future that’s where I’ll add the web framework and whatever else gets developed.

I plan to elaborate on the process manager more in a future post, but in short there are two parts:

  • The FastCGI server / process manager (coded in C). This accepts requests and manages and delegates to the workers.
  • The worker (coded in Julia). This listens for TCP connections from the FPM, accepts a bunch of commands and then runs the requested Julia page/code.

This way, there’s always a pre-loaded version of Julia in memory, circumventing any startup concerns (unless a worker crashes, of course).

Some early benchmarks

Now that the FPM is in a usable prerelease state, I wanted to see how it could perform compared to the alternatives. In this case, I chose PHP (obvious) and Python. I chose Python because the name often crops up in Julia discussions and there’s a FastCGI module available for it.

To run these tests, I used the Apache ab tool from my Windows machine. The server is a cheap 1-core VPS running CentOS 6 64-bit.

In all tests, the server software used was nginx. For the languages, I used PHP-FPM for PHP, Web.py for Python and the Jaylle FPM for Julia.

The individual tests are superficial and the results anecdotal, but I just wanted something to give me an idea of how my FPM performed by comparison. To elaborate:

  • Basic output: Printed “Hello, [name]” – with [name] taken from the query string (?name=…)
  • Looped arithmetic: Adding and outputting numbers in a loop with 7000 iterations.
  • Looped method calls: Calling arithmetic-performing methods from within a loop with 7000 iterations.

Below is a table of the results. The numbers shown are requests per second; higher is better.

Basic output Looped arithmetic Looped method calls
PHP 28.17 11.29 10.92
Web.py (Python) 24.61 7.92 7.25
Jaylle (Julia) 24.85 5.27 5.12

The only thing that I can say from these results is that I’m comforted seeing that my FPM’s performance isn’t obviously terrible compared to the others, but that there’s probably some work that does need to be done to at least get it up to the same level as Python, if not PHP.

In other news, I’ve realised (4 years late) that all the cool people use Twitter now. I therefore have started actively using my account. I can’t promise that following me will improve your quality of life, but feel free to give it a chance: @phollocks

Coming soon: FPM documentation + writeup (as soon as I’m comfortable enough to tag a release).

Revisiting emulated OOP behaviour and multiple dispatch in Julia

In an earlier post, I explored one approach to emulating bundling functionality with the data on which it operates, akin to object methods in OOP languages such as C# and PHP. A comment posted by Matthew Browne questioned whether this approach was compatible with Julia’s multiple dispatch.

This is something I thought about at the time of writing the original article, but I had assumed it wouldn’t be possible due to the way in which the anonymous functions are assigned to variables i.e. assigning one definition would overwrite the previous. However, Matthew’s question prompted me to reconsider – and after some brief experimentation and some small alterations, I found that there is indeed a way to maintain compatibility with multiple dispatch.

Below is an updated example type definition:

type MDTest
    method::Function

    function MDTest()
        this = new()

        function TestFunction(input::String)
            println(input)
        end

        function TestFunction(input::Int64)
            println(input * 10)
        end

        this.method = TestFunction

        return this
    end
end

The theory is basically the same, with the constructor assigning the methods to their respective fields within the type. The difference is in how the functions are defined and assigned.

On lines 7 and 11, methods are defined with different argument types. These methods could be defined outside of the type definition without error, but defining them within the constructor has the advantage of not polluting the global scope.

On line 15, the function is assigned to its field using some slightly different syntax, which allows both methods to be called.

With this, the example code below:

test = MDTest()

test.method("String")

test.method(5)

Produces the output:

String
50

Another advantage to this approach is the absence of anonymous functions – which, according to benchmarks and GitHub issues, have significantly worse performance compared to named functions.

Julia variable gotchas

As is typical for many languages, assigning one variable to another in Julia does not create a copy of the variable data, but rather a reference to the existing data. However, I learned the hard way whilst working on the CGI module that Julia does not currently support a copy-on-write mechanism for collections.

Take the example code below:

n = [ 1, 2, 3 ]

m = n

As expected, m becomes a reference to the collection referenced by n. Working with any number of mainstream languages, one might expect a copy to be made of the data referenced by n if either n or m is modified, for example:

n = [ 1, 2, 3 ]

m = n

push!(n, 4)

# Expect n = [ 1, 2, 3, 4 ] and m = [ 1, 2, 3 ]

This is not the case for Julia. When the array pointed to by n is modified, m maintains its reference to that same array, giving both a value of [ 1, 2, 3, 4 ].

Problems in the wild

I encountered this quirk when working with binary data and UTF-8 strings.

n = Uint8[ 0x32, 0x33, 0x34, 0x61 ]

m = utf8(n)

empty!(n)

Having created a string using the utf8 function, I wanted to empty the original byte array to free those resources. After a few minutes of trying to figure out how a bounds error had crept in to my app, I narrowed it down to this deletion of the byte array.

Digging deeper into the Julia source, the utf8 function is just an alias for a conversion function.

utf8(x) = convert(UTF8String, x)
...
convert(::Type{UTF8String}, a::Array{Uint8,1}) = is_valid_utf8(a) ? UTF8String(a) : ...

You can see here that passing an array of Uint8 bytes to utf8() creates an instance of UTF8String with the Uint8 array as its data. The type definition for UTF8String is:

immutable UTF8String <: String
    data::Array{Uint8,1}
end

As was covered above, the UTF8String’s data field will be only a reference to the collection passed to the utf8 function. If that collection is modified in any way at any point during the program’s runtime, so too will be the returned string.

In closing

It seems that the solution at this time is to explicitly use the copy or deepcopy functions, where copies of data are required by the program logic.

The issue is explored in this Google Groups thread. If I’ve understood correctly, the gist of it is that Julia makes this sacrifice for the sake of performance. As this is a feature wanted by many, there’s a possibility of it being implemented in a later version of the language.

Capturing output in Julia

In a previous blog post I pondered whether it may be possible to redirect STDERR to an IOBuffer so that the output can be handled in a controlled way e.g. written to a log file. It turns out that it’s not quite that simple, but capturing output can still be achieved easily with a few more lines of code.

The noteworthy functions here are the redirect_std* family of functions. These functions redirect their respective handles to a new pipe and return a read and write handle for said pipe.

Capturing output

Below is an example of capturing output to STDOUT.

(outRead, outWrite) = redirect_stdout()

print("Test")
print("ing")

close(outWrite)

data = readavailable(outRead)

close(outRead)

At the end of execution, the variable “data” will contain the string ‘Testing’.

(As seen on line 6, it’s advisable to close the write handle before trying to read from the pipe, as this will ensure that any buffered writes are flushed and available for reading.)

If you need to write to the original output stream after redirecting and capturing data, you’ll first need to create a copy of the original handle and restore it later. For example:

originalSTDOUT = STDOUT

(outRead, outWrite) = redirect_stdout()

print("Test")
print("ing")

close(outWrite)

data = readavailable(outRead)

close(outRead)

redirect_stdout(originalSTDOUT)

print(data)

Line 1 is where the original handle is copied; line 14 is where it’s restored. The print on line 16 will therefore write to the original STDOUT (e.g. console window, browser, etc) instead of the outWrite pipe.

Capturing errors

This technique is particularly useful when applied to STDERR, as it can be used to write errors to a log file. The process is the same, but instead using functions applicable to STDERR. Below is a slightly different example:

(errorRead, errorWrite) = redirect_stderr()

atexit(function ()
    close(errorWrite)

    errors = readavailable(errorRead)

    close(errorRead)

    logfile = open("errors.log", "a")
    write(logfile, errors)
    close(logfile)
end)

atexit registers a function to be called when the program execution ends for whatever reason (fatal error, user called the quit function, etc). The code between lines 4 and 8 is similar to the STDOUT example – and code as been added at lines 10 to 12 to log the captured error(s) to a file.

Understanding object-oriented programming in Julia – Inheritance (part 2)

In part 1, I explored the concept of objects from the perspective of the Julia language. In this article, I will be looking into Julia’s implementation of object inheritance i.e. the inheritance of behaviour and properties.

Classes / types

Read more at http://julia.readthedocs.org/en/latest/manual/types/

As was covered in part 1, the closest thing to a “class” or “object” in Julia is a type – which may contain fields (properties), but there is no support for including methods.

There are a number of different types, but the two most noteworthy for this article are abstract and concrete types.

Concrete types have a name, a list of fields and a constructor. Concrete types can be instantiated and used to store and manipulate information. These types are closest in behaviour to the traditional “classes” of object-oriented programming.

Abstract types have only a name and no other properties or behaviour. The purpose of abstract types seems to be as a way to indicate relationships between concrete types and can be thought of as being most similar to OOP interfaces than abstract classes.

(There also exist immutable types, which are essentially constants)

Inheritance

In Julia, all types are only able to “inherit” (i.e. be a subtype of) abstract types. This means that you could for example have an abstract type Letter which is inherited by concrete types A and B, but this would serve no other purpose than indicating that A and B are letters.

Having read the documentation and various contributor comments on the help forums, it appears that Julia was never intended to and will never support inheritance of either data or behaviour e.g. concrete types inheriting or extending other concrete types. The consensus appears to be that delegation is the preferred solution.

I began to look for a way to emulate the behaviour of concrete inheritance. As is often the case, the solution is an abomination. Still, for academic purposes…

Forcing inheritance of properties and behaviour

My plan was to find a way to merge two types together. I decided to create a method that, when two “Inheritable” objects are added together (i.e. “a + b”), will produce a new type containing the fields and data from both objects.

As of Julia 0.3, there’s no way to add field definitions to a type after the type has been declared. This meant I needed to create a new type declaration at runtime – which requires the use of an eval.

Sidenote: As if that’s not enough of a performance hit, the code here must first parse a text string containing the code for the type definition, which creates an Expr object that eval can then execute; it would therefore be possible to optimise the below code by directly manipulating an Expr’s args array, rather than relying on the parse function – but this is beyond my current Julia skillZ.

Below is a big chunk of code, which I’ll elaborate on:

abstract Inheritable

+(a::Inheritable, b::Inheritable) = (function (a::Inheritable, b::Inheritable)
    properties = Dict{String, Any}()

    for property in names(a)
        propertyName = string(property)

        if (!haskey(properties, propertyName))
            properties[propertyName] = (propertyName, string(fieldtype(a, property)))
        else
            (fieldName, fieldType) = properties[propertyName]
            properties[propertyName] = (fieldName, "Any")
        end
    end

    for property in names(b)
        propertyName = string(property)

        if (!haskey(properties, propertyName))
            properties[propertyName] = (propertyName, string(fieldtype(b, property)))
        else
            (fieldName, fieldType) = properties[propertyName]
            properties[propertyName] = (fieldName, "Any")
        end
    end

    fieldCode = ""

    for property in values(properties)
        (fieldName, fieldType) = property
        fieldCode = fieldCode * fieldName * "::" * fieldType * "\n"
    end

    randomTypeName = "An" * randstring(16);

    typeCode = "type " * randomTypeName * " <: Inheritable " * fieldCode * " function " * randomTypeName * "() return new () end end"

    eval(parse(typeCode))

    randomTypeName = symbol(randomTypeName)

    c = @eval begin
        $randomTypeName()
    end

    for property in names(a)
        try
            c.(property) = a.(property)
        catch
            c
        end
    end

    for property in names(b)
        try
            c.(property) = b.(property)
        catch
            c
        end
    end

    return c
end)(a, b)

This code contains an abstract type (“Inheritable”) and a method to handle the addition of one Inheritable object to another – the result being both objects merged together to form another Inheritable object.

The first two loops go through each object and create a record of their properties and the properties’ types. You’ll notice that if both objects have a property with the same name, the type is changed to Any to eliminate any conflicts between types e.g. one object accepting an integer and another accepting a float. In practice this is likely to cause a lot of headaches due to Julia’s multiple dispatch, but just roll with it.

Immediately after that, the properties are written into a string of Julia code as field definitions. A random name is generated for the new pseudotype, with care taken to ensure that the first letter is alphabetic (numbers will cause a parse error). The code for the type is then compiled together into a final string, parsed, evaluated and executed.

A second eval calls the pseudotype’s constructor, creating an incomplete instance of the new type.

Two more loops then iterate over the objects being merged together, assigning their current values to the properties on the new type. The resulting object is then returned.

Below is an example of two types making use of this emulated inheritance behaviour:

type A <: Inheritable
    whoAmI::Function
    uniqueFunctionA::Function

    function A()
        instance = new()

        instance.whoAmI = function ()
            println("I am object A")
        end

        instance.uniqueFunctionA = function ()
            println("Function unique to A")
        end

        return instance
    end
end

type B <: Inheritable
    whoAmI::Function
    uniqueFunctionB::Function

    function B()
        instance = new()

        instance.whoAmI = function ()
            println("I am object B")
        end

        instance.uniqueFunctionB = function ()
            println("Function unique to B")
        end

        return A() + instance
    end
end

Type A is a standard type declaration, using the same emulated method bundling from part 1. Type B extends type A in the constructor, by returning an instance of the merged pseudotype instead of an instance of type B. That code is:

return A() + instance

The below code is an example of using these two objects:

a = A()
a.whoAmI()

b = B()
b.whoAmI()

b.uniqueFunctionA()
b.uniqueFunctionB()

Which produces the output:

I am object A
I am object B
Function unique to A
Function unique to B

Issues remain unsolved

Even the above hack-around doesn’t solve the problem of visibility. The code carries an increased performance penalty to run, is less intuitive and not particularly elegant. At this stage, I don’t think Julia is suited to the same approaches and design patterns used in languages like PHP and C#. Is that a good or bad thing? In part 3 I’ll try doing things the “Julia way” and report back with any benefits or limitations I encounter.