The terse naming technique is one of the principal technique for reducing character count complexity metric, but it offers positive implications on the horizontal complexity as well. The technique dictates a replacement of long variable names with short, often one or two characters long, names. This is possible mostly in the case that the identifier represents a generic member of its kind. The code will obfuscated if such short names are used for non-generic members.
The following function takes a quadratic function, specified by the three coefficients of the polynomial, and draws the values of this function in several integral points.
void draw_Quadratic_function(
double coefficient_X_squared,
double coefficient_X,
double free_coefficient,
int points_count
) {
double values_array[] = new double[points_count];
for (int index = 0; index < points_count; index++)
values_array[index] = coefficient_Xsquared * index * index + coefficient_X * index + free_coefficient;
draw(values_array,points_count);
}
The parameters to this function are generic, that is, no special assumptions are made about any one of them. The first three parameters are arbitrary double
values, while the fourth is a non-negative integers. The terse naming technique dictates using one letter names for all of these:
void draw_quad_func(double a, double b, double c, int n) {
double f[] = new double[n];
for (int i = 0; i < n; i++)
f[i] = a * i * i + b * i + c;
draw(f,n);
}
The choice of names relies on common mathematical conventions for the names of the coefficients of a quadratic polynomial, and the use of n as a generic name for a generic non-negative integer.
This shorter former should be just as clear as its longer version. Further, the shorter form reveals a quick optimization by using Newtwon's formula for the evaluation of polynomials
void draw_quad_func(double a, double b, double c, int n) {
double f[] = new double[n];
for (int i = 0; i < n; i++)
f[i]=(a * i + b ) * i + c;
draw(f,n);
}
which incidentally reduces further the character count and the token count metrics.
As shown in the above example, trying to make up "good", in the sense of long, verbose and descriptive names for generic variables may yield somewhat awkward names such coefficient_X_squared
. It may also lead to inconsistent naming. Consider for example functions compareTo
and compareToIgnoreCase
/**
* Compares two strings lexicographically.
* The comparison is based on the...
* @param anotherString the String to be compared.
* @return ...
*/
public int compareTo(String anotherString) {
// ...
}
/**
* Compares two strings lexicographically, ignoring case
* differences...
* @param str the String to be compared.
* @return ...
*/
public int compareToIgnoreCase(String str) {
// ...
}
both of which are part of Java's standard implementation of the String
data type, that is java.lang.String
. In the first, the generic parameter is named anotherString
while in the other, it is named str
, even though the functions are similar, and both parameters serve the same role. Similarly, we find in the same class a function whose signature is
public boolean equals(Object anObject)
and another function with the signature
public boolean equalsIgnoreCase(String anotherString)
It seems as if the implementors of this class worked hard to find descriptive names for these generic parameters. But, almost by definition, generic entities have no descriptive names, and it is even more difficult to come up with consistent "descriptive" names for these.
The alternative offered by the generic names technique
public boolean equalsIgnoreCase(String anotherString) {
// ...
}
public int compareTo(String s) {
// ...
}
public int compareToIgnoreCase(String s) {
// ...
}
public boolean equals(Object o) {
// ...
}
public boolean equalsIgnoreCase(String s) {
// ...
}
is more consistent. And, the choice of one letter names highlights the fact that the values with which the receiver String
is compared are arbitrary.
In selecting generic names, apply the following rules:
Generic names should never be used for non-generic. Do not apply the following rules to any of these.
Consider for example the signature of function sendAnEmail
private static void sendEmail( final String from, final List<String> to, final String subject, final String body, final List<File> attachments ) throws Throwable {
Parameter from
is a String
, but it is not a generic string. The function is not designed to work if an arbitrary string is passed as its first parameter. Parameter from
is intended to be a string representing a valid email address and accordingly follow specific formatting rules, and the choice of name reflects this intention. A generic name for this parameter is absolutely inappropriate.
The same consideration applies to all other parameters of this function.
Terse names should never be used for variables defined in large scope
The generic identifiers technique is inspired by the observation that many of the identifiers are visible only at a very limited scope. The application of other spartan programming techniques may make this scope even shorter. But, if for some reason a variable is visible in a large scope, using a generic name for it may confuse readers, sending them in a long journey of examining the variable's definition and all its uses.
Generic names of variables of the primitive arithmetical types should follow the mathematical conventions suitable for the context.
The primitive arithmetical types of Java are byte
, short
, int
, long
, float
and double
. C++ offers more such types, including unsigned short
, long long int
, long double
. Generic variables of arithmetical types are often used in a mathematical context which suggests names for such variables.
Function positive in Class DBC uses the name n for a generic parameter of type int
/**
* A possibly non-returning method to be used for checking integers which must be positive.
*
* @param n
* a value which must be positive
* @throws Bug.Assertion.Value.Numerical.Positive
* in case n was nonpositive
*/
public static void positive(final int n) throws Bug.Assertion.Value.Numerical.Positive {
if (n <= 0)
throw new Bug.Assertion.Value.Numerical.Positive(n);
}
The standard Java library, java.lang.Math
includes a function to compute an angle from rectangular coordinates. This function reads
/** ...
* @param y the ordinate coordinate
* @param x the abscissa coordinate
* @return ...
*/
public static double atan2(double y, double x) {
// ...
}
There are only two non-arithmetical primitive types in Java: char
and boolean
.
A generic variable of type char
is usually denoted by c
as in the following two functions, both drawn from the Java standard library implementation of the type Character:
/**
* Returns a <tt>Character</tt> instance representing the specified
* <tt>char</tt> value. ...
* @param c a char value.
* @return a <tt>Character</tt> instance representing <tt>c</tt>. ...
*/
public static Character valueOf(char c) {
...
}
/**
* Returns a <tt>String</tt> object representing the
* specified <tt>char</tt>. ...
* @param c the <tt>char</tt> to be converted...
*/
public static String toString(char c) {
return String.valueOf(c);
}
Generic parameters of type boolean
are not common. When they do show up, the generic names technique says that they should be named b
as in the following example, drawn from the Java standard library implementation of the type Boolean
:
/**
* Returns a <tt>Boolean</tt> instance representing the specified
* <tt>boolean</tt> value. ....
*
* @param b a boolean value.
* @return a <tt>Boolean</tt> instance representing <tt>b</tt>. ...
*/
public static Boolean valueOf(boolean b) {
...
}
The name of an instance of a non-primitive type is the first letter of the type name, if the type name is a single word.
Good type names consist of a single word. A generic instance of an instance of such a type is the first letter of the type name.
For example, function sendMessage uses the generic name t for the generic variable of type Transport
private static void sendMessage(final Message m, final Session s) {
final Transport t = s.getTransport("smtp");
t.connect(smtpServer, port, userName, password);
t.sendMessage(m, m.getAllRecipients());
t.close();
}
The generic name of an instance of a non-primitive type whose name is comprised by several words is the lower cased acronym of the type name
The following function is offered by Java's standard implementation of the String
datatype, that is java.lang.String
. Notice that the generic parameter of type StringBuffer
is named sb
.
/**
* Compares this string to the specified {@code StringBuffer}...
*
* @param sb
* The {@code StringBuffer} to compare this {@code String} against
*
* @return ...
*/
public boolean contentEquals(StringBuffer sb) {
synchronized(sb) {
return contentEquals((CharSequence)sb);
}
}