Design Pattern the Julian way?

Design Patterns are the firsts building blocks when developing an application.
There are a few of them, most developers recognize or use them when building a medium/large application.
They are listed here: https://en.wikipedia.org/wiki/Software_design_pattern

I was wondering if there is something equivalent in Julia. Due to multiple dispatch which is a fundamental difference over OOP, I expect some variations, and maybe some patterns are just not applicable. Multiple Dispatch is a very powerful tool, a showcase (tutorial or book?) of what is possible to do would be very interesting.

Thanks!

5 Likes

In fact, multiple dispatch is so powerful that the usual OO “design patterns” are mostly not needed. Some studies were written about this for Common Lisp/Dylan, and most if it is applicable to Julia (even more so, since Julia’s parametric type system is more advanced in some directions).

See this well-known presentation by Peter Norvig. There is also a view that design patterns are boilerplate that reveal flaws in a language.

11 Likes

While what Tamas says is true that does not mean there are not design patterns for Julia. They are, however, different from the traditional OOP ones. The Julia documentation has a section dedicated to design patterns for parametric methods.

https://docs.julialang.org/en/v1/manual/methods/#Design-Patterns-with-Parametric-Methods-1

Things like Holy Traits and promotion rules, which promotes type stability and allowing the complier to better inline specific methods are the name of the game.

7 Likes

This is really fascinating. I’m excited to see how this continues to develop as Julia progresses. There are a lot of cool things about Julia, but one of the most fun things is how well positioned it is to discover and improve new programming paradigms. Transducers.jl is a great example of this (although not really a new approach it’s still neat that we can use it).

I can’t wait for the day that Julia has been around long enough that someone has the time to write a full book on these things.

3 Likes

Hi. I’m indeed writing a book about design patterns at the moment.

Please post any specific topics that you would like to see being covered. I already have a plan about the contents but when time permits I will try to accommodate topics that the developer community is interested in.

The Hands on Design Patterns for Julia book is slated to be published some time around the end of this year.

15 Likes

This looks pretty neat! One thing that would be really interesting is metaprogramming and intermediate representations of code, because Julia is uniquely positioned to address it.

Thank you all for your answers.

I read a lot of your different links, but I’m not sure I understood it well:
All the “classic OOP” patterns no longer exist in Julia? However, new design patterns related to multiple dispatch exist in Julia.
Does all these new patterns are described in this Julia doc page?

Also, the first paragraph states:

While complex dispatch logic is not required for performance or usability, sometimes it can be the best way to express some algorithm.

Does it mean that most of the time we should avoid implementing these design patterns?

I think it means that the more complex patterns aren’t required for new users to achieve usability. Although, there are some topics you occasionally find that are both more complex and less desirable for general usage (@pure is a perfect example of this).

3 Likes

Broadly, yes. The “design patterns” documented on that page are mostly about compile-time computation in type space, something more or less unique to Julia when combined with multiple dispatch in this way.

There is a wider range of what you can call “good practices”, not everything is documented on that page.

Julia is still evolving, how various patterns and interact with advanced usage (eg source-to-source transformations) is in flux, the compiler also keeps getting better of figuring out things without help. What you see described on that page is well-established usage.

In a sense, “design patterns” for Julia tend to be (1) more optional and (2) simpler than their OOP counterparts. You may be interested in

which explains why this is to a large extent.

4 Likes

Design patterns in functional programming

It’s sunday today,
Good stuff there to laugh a bit while prepping seriously next week.

fp%20design%20patterns%20w%20scott
Scott WLASCHIN, 2014

Thanks to Scott WLASCHIN for its work with F# to explain us better how to design with functional programming language. He also publishes :

Domain Modeling Made Functional
Scott WLASCHIN, 2018

Design patterns in programming

Clean Architecture
Robert MARTIN, 2017

Implementing Domain-Driven Design
Vaughn VERNON, 2013

are very, very good books about this matters.

Design Patterns anywhere

(Very) serious people can learn / enhance their skills about design patterns here too :

Analyzing Object-Oriented Design Patterns from an Object-Process Viewpoint
Dov DORI, 2006

FYI Dov Dori teaches at MIT/technion about modeling, systems engineering.
Nonetheless its thesis about Object Process Methodology became an ISO norm few years ago !
IMHO, that work encompasses and surpasses UML, maybe SysML too.

And now

Julia is sufficiently well grounded into science land to be very well accommodated with such methodologies. This famous talk in the the julia community about multidispatch given @ Juliacon can be watch before for a great introduction :

The Unreasonable Effectiveness of Multiple Dispatch
Stefan KARPINSKI, 2019

4 Likes

There is also some uncertainty in modules and packages organization for programmers who are rewriting in Julia large OOP codebases with many classes.

While some design patterns are genuinely useful, I still don’t think that they are the best way to become a proficient Julia programmer.

I recognize that for some languages, especially C++ & friends, design patterns have become an essential skill. Like many people, I see them as exposing a deficiency in these languages: lacking various abstractions, the programmers are required to implement some boilerplate, frequently “customized” for a particular problem, which means that the reader has to wade through 200+ LOC to spot those customizations.

I imagine that it is natural that programmers coming from C++, who have learned the a large set of these patterns, think that to learn Julia it is both necessary and mostly sufficient to learn a different set of “design patterns”. But I don’t think that Julia works this way:

  1. Julia has much more powerful abstractions with parametric types and multiple dispatch, and the general attitude in the community is to eliminate boilerplate code, not to formalize it,

  2. some patterns exist, but they are very “shallow” (frequently 2–5 LOC), and should be taken more like examples of various neat solutions that can be freely modified/combined, without insisting on identifying/formalizing the outcome as a “pattern”,

  3. The language is young, and not all patterns of use are widely explored, so it is perfectly possible for someone to come up with a powerful, succinct, and elegant solution to a problem that is not catalogued as a “pattern” by anyone. I see this on a daily basis on this forum. Knowing good examples is useful, but relying on them can be somewhat constraining.

For C++ programmers adapting to Julia, I would recommend making contributions to packages (or Julia itself). This is a great learning experience since it implies reading the source of a package, seeing a lot of examples of the idiomatic way of doing things, and finally getting an in-depth code review from experts (for free :wink:).

11 Likes

Patterns come from a swing between programming in the large and programming in the small.
They are only partially influenced by the language itself (by its paradigms, not punctuation).
They often answer to an engineering or business questions.
Extracting a field or a type is a too low level question in my sense to be considered as a pattern.

Julia is quite young, Julia packages even more younger. There is not so much programming in the large involved today but it will come.

Patterns are useful, not a magic bullet. But i believe you should know when you have one in front of you.

An example, the composite pattern
composite%20pattern
It’s encoding in UML and OPM compared.

Two more ones : chain of responsability and observer

UML was all the rage sometimes ago. But did not success so much.
OPM has been developed at MIT, Technion during decade, is very simple, short and synthetic.
Is an iso norm since 2015 and is teached to thousand of engineers every year at MIT mooc. Last but not least, is not entangled in OOP like UML.

I encourage you to appreciate its versability, expressivity thru conciness while keeping precision
Last example, a classification of patterns table

patterns%20classification

NB: an ellipse is a function, a square a data

1 Like

I disagree, there are some reasonable complex codebases. The obvious one is Julia itself with the standard libraries, but JuliaDiff is another major one.

That said, arguably the size of a single library or even a collection of them is not the right way to measure code size in Julia, since many packages can be used to form a coherent toolkit for some purpose, often without the intention of the original designers, or just with minor fixes.

This is the “unreasonable effectiveness” pointed out multiple times above. To have this in C++ & friends indeed does require a lot of planning, architectural decisions, and meta-modeling languages like the latest variation on UML. In contrast, in Julia it just happens, and people consider it a bug when it does not. I never cease to be amazed by this.

6 Likes

Some time ago, another book on OO on Julia was posted here: https://github.com/ninjaaron/oo-and-polymorphism-in-julia. Not sure if the project is alive, but may be helpful.

2 Likes

@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.

13 Likes

Thanks for this, maybe this kind of insight could glean some direction to this thread : Planning Large Projects