Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Perl6::Math::Matrix (Part 4: Naming Methods)

DZone's Guide to

Perl6::Math::Matrix (Part 4: Naming Methods)

Good code should be readable, so adhering to good naming conventions is something all developers should do. In this post, one dev tells how he goes about this process.

· Web Dev Zone ·
Free Resource

Jumpstart your Angular applications with Indigo.Design, a unified platform for visual design, UX prototyping, code generation, and app development.

While reflecting on how to write a good Perl 6 module, I thought a lot about how to properly name my methods. In this text, I want to summarize what served me wel, which is a direct continuation of the last part, where I wrote about when it is helpful that methods share one name.

Do (Not) Dare (to) Differ

In software engineering there exists a discipline called DDD, or Domain Driven Design, which is just an academic term for: "just use the language people of a certain field are used to." That just makes sense for effective communication, but why? (If psychology bores you, just skip the next two paragraphs).

If you're interested, look into the works of neurologists António Damásio and others. He found that only when emotions are attached will information be remembered at all. And to digest logical principles and connections and braid them into the knowledge web of your long-term memory is actually a demanding labor. No wonder information gets soaked up with personal emotions while doing that. And even less wonder that people are not keen to do that over and over and stick to a once learned meaning of a word. It will cause constant friction if you insist on using the same word in a different way or a different word for the same meaning, although the latter is less irritating.

The crucial part of this mechanism is: while reading about it, most people recognize that something of that nature happens, but very few recognize it while its taking place. They're just occupied with the content of their thinking because the rational mind probably can handle only a few bits of information at the same time. Meanwhile, we use a more emotional part of the brain to navigate the wider net of remembered information.

That is why using your module will be a much more pleasant experience if the names of methods, packages, and types are intuitively understandable or at least lead you in the right direction. Many in our industry demand a more intuitive API, but there is a rational thinking process that helps you to craft something that, in the end, will appear self-evident.

Math(ematica)

Since the package Math::Matrix is blatantly about mathematics we should use its language. Words like norm, determinant, identity, kernel, minor and many more are just borrowed from there to not confuse mathematicians or mislead programmers that later might reach for literature to know more. But even mathematics has its history and culture and, for instance, an adjugate matrix can also be called a classical adjoint or sometimes an adjunct. In that case, I went with adjugate because it's a recently used term, it's short, and I sensed the least potential for ambiguity with other existing methods.

Misunderstandings can also be reduced by naming the parameter properly. In part 3, for instance, I mentioned that we have a method $matrix.submatrix($m, $n) that works as described by this text book. Additionally, the multi method provides the syntax $matrix.submatrix( rows => (1..3), columns => (0..4)) as some sources also recognize that as a submatrix. The existence of the arguments increases the distinction between the use cases, and their denomination makes not only the second case clearer but also a third, which is more complex: $matrix.submatrix( rows => (3,1,2), columns => (0,1,4)) (get from top to bottom the fourth, second, and third row and from left to right the first, second and fifth column of the original matrix).

The second case also hinted at my suggestion to consider the cultural environment of mathematicians (for instance, popular software like Mathematica or Octave). The additional constructors mentioned in the third part were certainly inspired by such tools and aimed to service academics with the workflow they're used to.

Perl 6 makes it very easy to create custom operators and using Unicode for that is a none issue. That is why Math::Matrix also imports operators for much of the mathematical ops. To the trained eye ‖ $matrix ‖ is just natural and more intuitive to understand that $matrix.norm. To be mindful of people with less easy access to Unicode there are alternatives such as +$matrix as well. Even that was was a happy coincidence, since the prefix + in Perl 6 signifies the (single value) numeric context and this is the exact mathematical definition of a norm. However, the prefix in Perl 6 is expected to be the exact same thing, just negated. This means trouble since, on the one hand, a negated norm is like the negated size of an object — you almost never want to know that (and you still can get it with -+$matrix). And, on the other hand, it is very useful to negate all cell values, when doing Gaussian matrix manipulation (which is then also very intuitive to read for a mathematician).

To summarize: I made it a point here to maximize usefulness. This might upset some purists, but operators are syntactic sugar anyway. When it comes to the methods of basic functionality I would be much stricter.

Perl 6

The other culture informing our API is naturally the language we use, Perl 6. This shows, in detail, for instance, we can write is-zero instead of is_zero (as we would in Perl 5). The dash is much better at signaling "this is one combined name" and commonplace in the core language. It was not an option in Perl 5, where we had to use the under_score or camelCase (still used for module names). A standard that still holds is to use lower case for ordinary methods (uppercase signifies danger). But, on one occasion, I broke this rule, when choosing T as a shortcut for creating a transposed matrix. It looks more like an Operator anyway (just on the letter) and was a too well-established symbol in math anyway.

Value vs. Container

Perl 6 has data types (Int, Str, Bool, ..etc.) and container types (Scalar, Array, Hash), that hold the former. The data objects are immutable to get all sorts of goodies, as functional languages have discovered. In part one, I wrote that it was one basic decision to see a matrix as a data type, i.e. immutable. Our documentation says so clearly, but I think it is also a good idea to craft method names cautiously so that the user will get that intuitively. This is the reason why the long form of T spells transposed and not transpose. You will create a transposed matrix, but the original will stay unchanged.

Lists and Arrays

Sometimes you want to prepend, append, or insert some rows or columns or even remove parts — sounds like a lot of methods to bloat our already very rich API. This is why I used a metaphor, well known to every Perl 5 and Perl 6 programmer, called splice. It is the Swiss army knife to make all kinds changes to a list: push, pop, shift, insert and remove are just special cases of what this command is capable of. So I implemented splice-rows and splice-columns which work exactly like expected, in the one dimension of the table, the new commands are named after.

With map I went even a step further because it is such a corner stone of Perl programming. Usually, map takes a list (we prefer to say an array), transforms every element via an anonymous block and returns a list with the results. Nothing stops you from writing $resultlist = $matrix.list.map: {...};. But often, you want to preserve the structure of the matrix and get a new one, just made of the results. That I called boldly map, too, since it maps over each cell and (as the original) returns the same collective type as you put in and this way using the metaphor of map a little looser. As any normal Perl-programmer, you expect the current cell value inside the anonymous block to be $_, so you can even nicely call it $^anyname in Perl 6. But, I found, that for some transformations of matrices, you also need the current row and column index of the cell while doing a map. But this would be a too big departure from the original metaphor. This difference has to to be sufficiently visible, as I named it map-with-index.

Conclusio 

To create an enjoyable API, draw on familiar and established names, naming standards, workflows, and metaphors. That might even outweigh, in rare cases, consistency — but never sacrifice necessary innovation.

Take a look at an Indigo.Design sample application to learn more about how apps are created with design to code software.

Topics:
web dev ,perl ,naming methods ,devlife ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}