Pearl Code Guide
- Transfer
Of course, each programmer has their own preferences regarding formatting, but there are some general principles that follow make your programs easy to read, understand and maintain.
The main trick is that your programs should always run with a flag
-w
. If necessary, you can purposefully disable this action for specific sections of code through pragmas no warnings
or a variable $^W
. Also, you should always run programs using use strict
, or clearly understand why you are not doing this. Pragma use sigtrap
and use diagnostics
can also be useful.As for the aesthetics of code design, the only thing Larry seriously cares about is that the closing brace of the multi-line block should be vertically aligned with the keyword starting the whole construction. In addition, he has other preferences that are not so serious:
- Indentation in 4 columns.
- The opening brace, if possible, on the same line as the keyword, otherwise vertically aligned with it.
- Space before the opening brace in a multi-line block.
- A single line block can be placed on one line, including braces.
- There are no spaces before the semicolon.
- The semicolon is omitted in the “short” single-line blocks.
- Spaces around most operators.
- Spaces around “complex” structures (inside braces).
- Empty lines between pieces of code that perform different tasks.
- Non-snapping
else
.
- There are no spaces between the function name and the opening bracket.
- Spaces after each comma.
- Long lines break after operators (excluding
and
andor
).
- After the last closing parenthesis, the line must contain a space.
- Align similar elements vertically.
- Omit excessive punctuation if clarity does not suffer.
Larry has a rationale for all of these things, but he does not claim that everyone reasons the same way he does.
Here are a few other, more significant design issues to consider:
- If you CAN DO something in a specific way, this does not mean that you SHOULD do just that. Pearl is designed to give you several ways to do the same thing, try to choose from these methods more visual. For example, this:
open(FOO,$foo) || die "Can't open $foo: $!";
better than this:die "Can't open $foo: $!" unless open(FOO,$foo);
because the second option hides the main meaning of this expression in the condition. On the other hand,print "Starting analysis\n" if $verbose;
better than$verbose && print "Starting analysis\n";
because the point here is not whether the user typed-v
or not.
Similarly, if the operator has arguments with default values, this does not mean that you need to use them. The default values are for lazy system programmers writing one-time programs. If you want your program to be easy to read, consider using arguments.
Again, the fact that you CAN omit the brackets in many places does not mean that this should be done. Compare:return print reverse sort num values %array; return print(reverse(sort num (values(%array))));
If in doubt, put brackets. At least this will allow some poor fellow to poke the key%
atvi
.
Even if you have no doubt, think about the mental balance of the person who will maintain the code after you, and who will probably put the brackets in the wrong place.
- Do not make senseless passes through the cycle from top to bottom, because Pearl provides an operator
last
that allows you to exit in the middle. Just make a small “indent” to show this more clearly:LINE: for (;;) { statements; last LINE if $foo; next LINE if /^#/; statements; }
- Do not be afraid to use loop labels - they are there for convenience, as well as to interrupt multi-level loops. See the previous example.
- Avoid using
grep()
,map()
or `backticks` in an empty context, when you simply throw away the values they return. All of these functions return values, so use them. Or use a loopforeach()
or functionsystem()
.
- For portability, if you use some functions that may not be implemented on some machines, test these constructions in eval to see errors that occur. If you know in which version or in which patch the necessary function is implemented, check
$]
($PERL_VERSION
in the moduleEnglish
) to see if it is there. The moduleConfig
also allows you to find out the values defined by the programConfigure
when installing Pearl.
- Choose catchy identifiers. If you cannot remember what your reminder means, you have a problem.
- If short identifiers of a type are
$gotit
quite acceptable, then long identifiers should use underscores to separate words. It is usually much easier to read$var_names_like_this
than$VarNamesLikeThis
, especially for those for whom English is not native.
Package names have some exceptions to this rule. Pearl unofficially reserves module names in lower case for pragmas such asinteger
orstrict
. Other modules must start with a capital letter and use mixed case, if possible without underscores, due to the limitations of primitive file systems in which the names of files representing the modules must be written in several bytes.
- You may find it helpful to use a register to indicate scope or assign a variable. For instance:
$ALL_CAPS_HERE только константы (остерегайтесь конфликта со встроенными переменными Перла) $Some_Caps_Here глобальные и статические переменные $no_caps_here переменные, ограниченные областью видимости
Function and method names seem to work best in lowercase. Eg$obj->as_string()
.
You can use leading underscores to indicate that this variable or function should not be used outside the package in which they are declared.
- If you have a really fancy regular expression, use a modifier
/x
and add some spaces so that the expression does not look so scary. Do not use a slash as a delimiter if the regular expression itself contains slashes or backslashes.
- Use the new operators
and
andor
to get rid of too many brackets in the scheduled operators, as well as in order not to complicate the reading of punctuation operators like&&
and||
. Call your routines just as if they were functions or list operators to get rid of extra brackets and ampersands.
- Use here documents instead of re-writing
print()
.
- Align similar elements vertically, especially in designs that are still too long to fit on one line.
$IDX = $ST_MTIME; $IDX = $ST_ATIME if $opt_u; $IDX = $ST_CTIME if $opt_c; $IDX = $ST_SIZE if $opt_s; mkdir $tmpdir, 0700 or die "can't mkdir $tmpdir: $!"; chdir($tmpdir) or die "can't chdir $tmpdir: $!"; mkdir 'tmp', 0777 or die "can't mkdir $tmpdir/tmp: $!";
- Always check the system call return code. A good error message should be sent to
STDERR
and include an indication of which program caused the problem, which system call and with what arguments the error was executed, and (VERY IMPORTANT), it should contain a standard system message about what went wrong So. Here is a simple but comprehensive example:opendir(D, $dir) or die "can't opendir $dir: $!";
- Align the broadcast characters vertically when it makes sense:
tr [abc] [xyz];
- Think about reuse. Why waste your mind power on a one-time exhaust, if you can do something that will work again and again? Try to summarize your code. Try to write a module or class. Try to make your script work cleaner with
use strict
anduse warnings
(or-w
). Try to share your code. Try to change your view of the world. Try ... well, okay.
- Try documenting the code and using the Pod format on an ongoing basis. There are several general conventions:
- Use
C<>
for names of functions, variables and modules (and generally everything that can be considered part of the code, such as file descriptors or special values). Note that function names are easier to read if they have brackets after the name, such as -function()
.
- Use
B<>
for team names such ascat
orgrep
.
- Use
F<>
orC<>
for file names.F<>
It should be the only Pod code for file names, but most Pod converters display it in italics, which is why Unix and Windows paths containing forward and backward slashes may look poorly readable and useC<>
looks preferable.
- Use
- Be consistent.
- Be cool.