Design Pattern the Julian way?

@vpetukhov Well, it isn’t “dead”! I plan to update syntax and examples when and if language changes require it, but I’m not actively working on adding new material, though I’m thinking maybe I should add some stuff about modules. Thanks for the mention.

I was going to jump in here and mention my guide (I wouldn’t quite call it a “book”), but also that simply using the word “object oriented” in the title was quite controversial with some people! (c.f. I wrote a guide about Object Orientation and Polymorphism in Julia. opinions wanted!) I would point out that @ChrisRackauckas wrote a blog post covering many of the same patterns, but didn’t get the same kind of push-back on the topic, because he presented them as an alternative to OO, where I presented them as a special case of OO. Chris’ post is here: Type-Dispatch Design: Post Object-Oriented Programming for Julia

Anyway, no matter what you call it, Chris’ guide and mine are both good general introductions to designing types and interfaces in Julia, though nowhere near as a extensive as the gang of four book.

One thing to keep in mind, and other posts have touched on this, is that a lot of the gang of four patterns are about ways to achieve polymorphism and flexibility in statically-typed, strict OO environment like Java or C++.

As a dynamically-typed language, Julia gets a lot of this polymorphism for free. For example, the factory pattern is meaningless in Julia, since functions are allowed to return arbitrary types. One typically doesn’t need to design hierarchies of types, because any types that have all the required methods can be used interchangeably, regardless of their, uh, “heritage”. Inheritance in Julia is merely a tool for code reuse, since functions are polymorphic by default.

Other principles in gang of four are simply built directly into the language. For example, the emphasis on using interfaces over inheritance (programming to an interface rather than an implementation) is the only way to do inheritance in Julia, since it is only possible to inherit from abstract types, which provide only methods, not internal data layout.

For this reason, Julia programmers also tend to rely on composition more than inheritance. Method forwarding is a common strategy to make this easier.

Another concern in design patterns is encapsulation, in the sense of providing an interface that doesn’t allow the client to rely on implementation details of the API. One could argue, and I think I’d agree, that this is one area where Julia is a bit lacking. Nothing is private in Julia. It’s the responsibility of the programmer not to poke around in the implementation of other people’s modules, not to access struct fields unless invited, and not to commit “type piracy” (extending functions that aren’t yours to dispatch on types that aren’t yours). Unfortunately, there are a lot of examples of people ignoring proper etiquette in these matters.

On the other hand, this kind of encapsulation isn’t necessarily as essential in Julia as it is in languages like Java. For one thing, types in Julia, aside from collections, tend to be immutable. You can look at the parts, but you can’t stick your hand in the lawnmower while it’s running, so to speak. Disallowing inheritance of data layout in types also means you’re less likely have code that’s cutting cross-wise into some freaky layer cake of complexity. What you see is what you get.

Another element here is culture. Though Julia is not a functional language (collections are almost always built up with side effects), it has good support for many functional programming techniques and the community tends to favor a functional programming style. Specifically, programs tend to be structured in terms of sequences of data flowing through a processing pipeline, not in terms of defining object relationships. For this reason, composite types in Julia tend to be much simpler and less prone to abuse–though there are definite exceptions, and I think some kind of privacy enforced at the module level would be a useful feature.

I’m working on a companion to my OO guide about functional patterns in Julia. Suffice it to say that, pervasiveness of arrays and loops notwithstanding, idiomatic Julia is structured much more like Lisp than Java–and the same is true in good code in any dynamic language: Python, JS, Ruby, etc. Julia’s type system also lends itself to some interesting patterns that normally occur in statically-typed functional languages: multiple dispatch as a mechanism for pattern matching, for example, which has also lead to the trait pattern (and the trait pattern in Julia is definitely a case of a pattern being boilerplate to compensate for a missing language feature).

Anyone interested in idiomatic Julia would benefit from a general study on patterns in functional programming.

14 Likes