Commentary on why Perl 6 makes complex mutators hard to write

zaki
Sun, 27 Nov 2016 09:07:52 +0000
object-oriented programming, perl 6 programming language

Link: "Perl 6 is biased towards mutators being really simple. That’s a good thing." by Jonathan Worthington.

I just read over this post about one aspect of Perl 6's design decisions.

The title is a little ambiguous. It's not saying that "Perl 6 makes it easy to create mutators", but that "Perl 6 pushes the programmer towards keeping mutators simple in behaviour".

This alternate title is little longer, but is necessary because the topic can not be simplified to a pithy statement. The article talks about approaching OO design by focusing on passing messages between objects rather than treating objects as bundles of data that happen to have methods attached. This leads to less coupling and uses OO in a way that makes it easier to refactor since the conversation between objects has to follow a particular protocol as opposed to depending on the underlying data structure.

Many modern languages allow for making attributes such that when you assign to them like

my_object.my_attribute = value;

it actually calls a mutator method that can do something more complex such as validation. Aesthetically, this syntax looks appealing because it looks like a simple assignment, but when using this in an OO context, you're making a tradeoff.

Firstly, you are exposing the internal implementation of your objects. Sure, you can make it just a facade to a more complex internal representation, but that is also a mistake. When something looks that simple, it hides a lot of semantics. What if it throws an exception? Programmers don't expect an assignment to throw an exception, so the users of the interface may use it incorrectly. Furthermore, if you later want to substitute on object for another as part of refactoring, that new object will have to conform to the same interface as the original and that may not be appropriate.

You are essentially forcing the conversation between objects into a much narrower hole instead of placing behaviour before structure.

In Perl 6, attributes are private by default. It takes a little extra work to make attributes writable (you have to tack on the is rw trait). This allows a line like

$obj.my_attr = $value;

to work. However, this does not do anything complex behind the scenes. All it does is write to that attribute. Jonathan Worthington explains that this is by design.

This is surprising because one of the principles of Perl's design philosophy is TIMTOWDI. Surely there is room for writing custom mutators in there? As Jonathan Worthington points out, you are welcome to do this through other means. Those other means require extra scaffolding that discourages their use unless your are solving a problem that really requires them.

From my understanding, the TIMTOWDI part of Perl philosophy arises in Perl 6 because it allows the programmer to use multiple programming paradigms when appropriate. When writing procedural code, it is fine to use simple assignment for record data structures. When using the OO paradigm, a custom mutator is out of place — there are better solutions available and those are easy to implement. Attribute mutators are poor substitutes for well-named methods.

For example, if you desire a shorthand for working with your objects, Perl 6 allows for custom operators. It is not necessary to make operators like '=', '+', or '+=' do more than their original purpose. Just make another operator that makes more sense for your domain. Those operators can even be words; one of the ones that is built-in is gcd:

> 54 gcd 24
6

The main takeaway is that, when using OO, focus on behaviour first. This helps with testing and makes your code more malleable.