A piggy bank of commands, fixes, succinct reviews, some mini articles and technical opinions from a (mostly) Perl developer.

Jump to

Quick reference

Showing posts with label string. Show all posts
Showing posts with label string. Show all posts

Wrap those magic data structures with a class

You understand the the dangers of using magic numbers in your code. And magic strings are another face of the same issue. When you use a lot of strings that have special meanings, it makes your code smell bad, i.e. it's an indication of low quality. These are not user messages or log messages, but rather a fixed string that if mis-typed will break the systems functionality. But it's not just the basic variable types that are magic. Arrays and hashes can also be magic, in the worst possible way.

If you find yourself using a hash in a lot of different places, this can be thought of as a magic hash. It may be a simple hash or it may contain many nested arrays and other sub-hashes. Every operation on the hash has to be done in exactly the right way or it won't work. It's very easy to perform a operation wrong and get unexpected results that won't be detected immediately. You're writing a significant amount of code to read and write the data within the hash, and to catch errors, and you're likely to be creating bugs too. The more code you write, the more bugs you create. This similar, duplicated and boring boilerplate code is spread around all over the application wherever the hash is used. It's also likely that you will need to use magic strings for the hash keys, with all the problems they bring. Even if you use an array at the top level, there may be hashes within it.

The solution is to put a class around the hash, so that you only need to write the hash manipulation code once, and can thoroughly unit test it. All the code related to this data is encapsulated in one place. All calling code will interact with the class interface instead of the hash directly. This is an example of object-oriented development, where objects are passed around and manipulated instead of raw data structures.

P.S. Even without using a class, replacing magic strings with constants would be a serious improvement. Maintainers will be unable to accidentally get a string wrong without seeing an error message that makes it very obvious what is wrong. It's a more foolproof way to develop.

Regex anchors in Perl

A lot of the time it seems that Perl programmers write a regex like

/^foo$/

(where “foo” is some arbitrary regex pattern)

but from the context it seems like the intention of the programmer was to make it so that the string to be searched must match the pattern “foo”, and there must be nothing between the beginning of “foo” and the beginning of the string to be searched, and there must be nothing between the end of “foo” and the end of the string to be searched.

But of course the regex doesn’t do that.

The metacharacter ‘$’ matches not only at the end of the string to be searched but also just before a newline character at the end of the string to be searched. (Of course when the ‘m’ flag is specified, ‘$’ behaves differently. But I’d like to concentrate on the behaviour without the ‘m’ flag for the time being.)

So the above pattern will match “foo” and “foo\n”.

Is that what the programmer really wanted? I think in many cases not.

So how can we make the pattern match exactly at the end of the string to be searched?

The answer is to use the metacharacter ‘\z’. This matches exactly at the end of the string to be searched.

So to make a regex that matches the pattern “foo”, and with the beginning and end of the pattern bound to the end of the string to be searched, we could write:

/^foo\z/

=====
Here endeth the bit about doing the minimum to make the code correctly reflect the intention of the programmer. The rest is about style, personal preference, readability, etc.
=====

Some might say that using ‘^’ to match the beginning of the string to be searched and ‘\z’ at the end is a bit dicey because the meaning of ‘^’ is changed if the ‘m’ flag is used but the meaning of ‘\z’ isn’t. It would be nice if there was a metacharacter which exactly matched the beginning of the string to be searched, regardless of the ‘m’ flag. Fortunately there is, ‘\A’. Using that would give:

/\Afoo\z/

But because ‘\A’ ends with a letter, the regex can be a bit hard to parse if the ‘\A’ is followed by a pattern which begins with a letter. So some might say that it might be a good idea to use the ‘x’ flag to allow whitespace inside the regex. That would give

/ \A foo \z /x

Though I find it a bit hard to read when slash delimiters are combined with a few initial-backslash metacharacters, so I prefer to use a different delimiter. So I would think to use something like:

m{ \A foo \z }x

- by Bill Blunn
See also http://perldoc.perl.org/perlre.html#Regular-Expressions