Compiler Test

Naive BondageAndDisciplineLanguage afficianadoes claim that the compiler can prevent most bugs before they occur; ergo you don't need to worry so much about ProgrammerTests. This is of course silly and the afficianadoes will disclaim it ... while still sticking up for such tommyrot as ConstCorrectness ...

A CompilerTest is a test the compiler performs to tell you whether or not your code is correct. If these tests really did very much for you there'd be no way to work in DynamicLanguages at all ...

You can also UseAssertions to extend the compile-time checking towards domain problems. ... you can even use CompileTimeAssertion?s. Those qualify as CompilerTests, too.


A straw-man argument is presented above. The presence of CompilerTests is correlated with BondageAndDisciplineLanguages, but not causally so.

Whether a programming language is a 'BondageAndDisciplineLanguage' is determined by the set of requirements imposed upon the programmer, not by the requirements imposed upon the compiler or interpreter. CompilerTests are, fundamentally, requirements imposed upon the compiler. Only when this requirement imposes itself upon the user of the language does it become a BondageAndDiscipline issue (e.g. requirements for manifest types and explicit declaration of 'const'). If a language or project requires that you write UnitTests to eliminate bugs, that is just another form of 'bondage and discipline', just like the requirement to use HungarianNotation or to declare manifest types or put the 'const' keyword everywhere in your code.

It is possible to shift much more of the burden to the compiler for such things as TypeSafety, CompileTimeAssertion?s, and arbitrary constraints proofs (including ConstCorrectness in StateOrientedLanguage?s). Type inference is a partial approach (albeit an incorrect one in that implicit, static TypeSafety neither requires nor implies TypeInference, and TypeSafety is what is really desired). Even syntactic burden can be shifted. It is ridiculous that, given the computing power available today, languages are still designed as context-free LR(k) or LALR in order to speed up interpretation at the cost of programmer expressiveness.

What is the opposite of 'bondage and discipline'? 'freedom and anarchy'? I'm not sure, but whatever it is will enable instead of require. And among the things a good FreedomAndAnarchyLanguage? will enable are UnitTests and CompilerTests.


languages are still designed as context-free LR(k) or LALR in order to speed up interpretation at the cost of programmer expressiveness.

You imply that there cannot be programmer expressiveness with limited grammars. How, then, do you explain LispLanguage, which has one of the simplest syntaxes around, and is generally regarded as very programmer expressive?

You mistake my statement. I do not mean to imply that a language with a limited grammar cannot be programmer-expressive. Such a statement is easily falsifiable by pointing to any programming language capable of expressing anything at all... even TuringTarpits like BrainFuck. I mean only that the choices that limit syntax, such as to a ContextFreeGrammar?, will necessarily limit a language's potential for programmer expression; it gains you compilation speed at a cost to potential programmer expressiveness. (Perhaps I should have originally worded it thus. It doesn't cost all programmer expressiveness... just a massive chunk of the upper potential for it.) From a programmer's POV, all source code really is is one big expression of intention and suggestions as to implementation formatted in a manner that can be understood by the computer. Limitations imposed upon this expression are limitations to programmer expressiveness.

The 'expressive power' of a language is determined by the set of concepts a language can meaningfully express... though most often investigated in the negative. 'Meaningful' here pretty much means: comments don't count; the interpreter of the language must do something useful with the expression. E.g. BrainFuck cannot meaningfully express that a particular string represents a procedure that is intended to accept a sequence of integers that, themselves, represent a string. Standard C++ cannot meaningfully express that a procedure is intended to accept a string of a particular format, or that the procedure associated with a given interface is functional and may not have side-effects, or that a particular protocol requires a handshake of three message swaps and anything else is a programmer error, or that a particular data-unit is 'secret'-level and must not under any circumstances be passed beyond program boundaries. Language expressiveness is determined entirely by choice of primitives, grammar, and the defined evaluation stages (including macro-expansion, type-checking, constraints evaluation, partial evaluation, etc).

Programmer expressiveness with a given language is somewhat different from language expressiveness, though necessarily limited by it; it is the ability of a programmer to express intention directly... and is best seen in DomainSpecificLanguages where the 'programmers' (experts in some field) express exactly what they want to express without messing with the underlying details. Among those "underlying details" is the language atop which the DSL is implemented... so every single place the programmer (expert in his field) must translate to the DSL due to limitations of the underlying language qualifies as a weakness in expressiveness of the underlying language (in particular in its ability to support DSLs): such a translation is a layer of indirection. Fewer layers of indirection is better than many, of course... and programmer expressiveness can be enhanced considerably by judicious use of macros. However, the ability of the programmer to express a particular macro is also limited by the language; support for macros is, after all, another language primitive.

Suppose you are in the position to design a new language. By choosing a ContextFree? grammar, you gain support for the common LR(k) and LALR parsers that are out there... a major boon to implementing your new language, certainly! However, you have also limited certain forms of programmer expressiveness from ever becoming part of your language. E.g. if you allow programmers to create macros to perform 'operator overloading' (really a form of syntax overloading), the operators will not be able to change order-of-operations based upon the types of the parameters involved; you'd be stuck with one order-of-operations for all domains... which any C++ pundit will tell you is a sometimes painful limitation of the language. A programmer using the language has, thus, had his or her expressiveness limited. There are other examples, of course... any time the programmer might want a particular expression to have one meaning in one context and another meaning in another context, use of a ContextFreeGrammar? will eliminate that possibility.

Lisp is more expressive than C++, and is supported by a wide set of macro packages that enhance programmer expressiveness, but I wouldn't state that it is particularly expressive (relative to research languages). There are, of course, syntax issues... one is stuck with the parentheses-form even for macros and can't even begin to choose order-of-operations for matrix operations as opposed to integer operations. Beyond that, there are tons of limitations in language expressiveness that affect the programmer... the programmer cannot, for example, meaningfully express component-interfaces or communications-protocols or that a proposed implementation must meet a certain specification. One cannot declare, even indirectly, that a particular folder filled with SQL files is to have each file read at compile-time, interpreted and type-checked with some function, optimized, and stored into another procedure. Lisp lacks the primitives for CompilerTests, MultiStageProgramming?, distributed communications, and most forms of whole-program constraints & transformations.

I consider the choice of CFG to be a premature optimization in language design and consider the (usually linear but sometimes exponential) costs of heuristic backtracking search to be well worth the gains obtained in the creation of DSLs within another language. This presupposes, of course, that the language provides a macro-system capable of adding the full range of new syntax! Without such a macro system, the presence or absence of CFG is entirely irrelevant because the programmer is still limited to whatever syntax the base language provides. It's when you start trying to build a macro-system capable of supporting a vast array of DSLs embedded atop another language that the weaknesses of limiting oneself to a CFG become most obvious.


EditText of this page (last edited April 26, 2007) or FindPage with title or text search