No matter how restrictive a language is, some programmers will still find ways to screw things up. Imagine the following piece of code:
var price = this.ApplyVAT(basePrice);
if (this.acceptsRebate)
{
return new RebateCalculator(RebateType.Default).Transform(price);
}
return price;
Let's screw it:
// Rebats calculator became variable cal.
var cal = new RebateCalculator(RebateType.Default);
// stylecop complain if i dont put comment here and leave line empty. don't know why??
//
// don't know price now so later maybe!!!
Price pp = null;
// Func is transforms price to price!
Func<Price, Price> tar = cal.Do;
var g = Tax(bPR);
// changed by MAG 02/08/2013
// if arebt2 is true, the condition should match.....
if (arebt2)
{
// assign g to g2
var g2 = g;
// don't remember what tar mean but its very important!!! don't remove!!!
pp = tar(g);
}
else
{
// it's the same!
pp = g;
}
// i can return now because i know price!!!
return pp;
The code still complies to the same IL, and doesn't violate any StyleCop or Code analysis rules (while StyleCop is damn strict forcing you to write code in a very precise way). But it's now a piece of crap, completely impossible to work with. How would you possibly design a language which tells that those comments are useless and annoying, that my naming conventions is among the poorest and that intermediary variables add more harm than good?
Using Unicode in names is a good example. In the code above, I haven't even used Unicode in the names of variables. [A-Za-z0-9_]
is enough to give meaningless names. On the other hand, Unicode may be very helpful in improving code. This piece of code:
const numeric Pi = 3.1415926535897932384626433832795;
numeric firstAlpha = deltaY / deltaX + Pi;
numeric secondAlpha = this.Compute(firstAlpha);
Assert.Equals(math.Infinity, secondAlpha);
is readable enough, but allowing Unicode in names can empower the programmer to write this instead (the problem being that you won't be able to type variable names on a non-Greek keyword):
const numeric π = 3.1415926535897932384626433832795;
numeric α₁ = Δy / Δx + π;
numeric α₂ = this.Compute(α₁);
Assert.Equals(math.∞, α₂);
Some developers will consider that the second variant pushes naming too far, but it may be an excellent readability boost for some projects (such as a project written by a team of scientists).
Talking about naming conventions, I haven't seen a single rule which actually prevents giving bad names to variables. An example such as the code above can be prevented by a rule similar to:
The names of private variables should contain at least four characters. The names of public variables should contain at least six characters.
But this won't prevent renaming pp
into ppppppp
just to get rid of the warning. An additional rule:
The names can't contain a character consecutively repeated more than two times. For example, feed
is a valid name, while feeed
is not.
may also be circumvented by renaming the variable to ppabcde
.
The actual goal
What's more important is that a well designed programming language should help avoiding errors. For example:
if (this.isEnabled)
this.PlayVideo();
this.PlaySubtitles();
is a sign that something went wrong. When I see that in a C# code, I blame:
The programmer, because it's so simple to always insert curly brackets, instead of taking a risk of losing thousands of dollars because of a stupid bug, hard to detect during code reviews and hard to find later,
The programmer, again, because he should have used proper tools (StyleCop in this case),
The language, because such syntax could have been forbidden,
The IDE, because it didn't reacted to the fact that the programmer screwed up indentation.
Conclusion
Be restrictive when it helps avoiding bugs and when the syntax flexibility is not particularly useful.
Don't be restrictive just to help beginners: they'll find ways to make their code unreadable anyway.
Add syntactic sugar when it helps readability most of the time, without being misused most of the time.
Example of Python
If you know Python, this is a good example of useful strictness. Persons who just started learning it are usually negatively surprised by its strictness:
What? I can't indent the code like I want? This is annoying!
or:
There are no switch statements in Python? Are you serious?! Are you telling that I have to use if-elif-else
every time I need a switch?
A few years later, the person would confirm that:
Having meaningful indentation is an excellent idea, because it prevents subtle errors (like the one with the if
above) and reduces the effort of writing code (instead of putting semicolons and indenting code, you deal only with indentation).
They don't need a switch, because they replace conditional by polymorphism anyway and when they actually need a mechanism similar to a switch
, a dictionary is a perfect choice.