What are practical guidelines for evaluating a language's "Turing Completeness"?
Solution 1:
You need some form of dynamic allocation construct (malloc
ornew
or cons
will do) and either recursive functions or some other way of writing an infinite loop. If you have those and can do anything at all interesting, you're almost certainly Turing-complete.
The lambda calculus is equivalent in power to a Turing machine, and if you implement lambda calculus it is actually pretty fun writing lambda calculus programs. Way more fun than writing program for a Turing machine!
The only practical implication of Turing-completeness I'm aware of is that you can write programs that don't terminate. I've used a couple of special-purpose languages that guarantee termination and therefore are not Turing-complete. Sometimes it is useful to give up the extra expressive power in exchange for guaranteed termination.
Solution 2:
'Turing Completeness' describes the property of being able to express any arbitrary algorithmic computation, which was the point of Turing's Machine in the first place. A language or logical system can be described as 'Turing Complete' if it has this property. From a practical perspective all general purpose programming languages - and a surprisingly large number of special purpose ones - can do this for a suitably loose definition (see below).
However, a strict definition of Turing Completeness implies infinite storage capacity, which is of course not physically possible. Given this, no physical machine can possibly be Turing Complete, but this constraint is usually relaxed (at least informally) when ascribing Turing Completeness to a programming language. One trivial test of Turing Completeness for a language is whether the language can be used to implement a Turing Machine simulator.
An example of a widespread system that is not Turing Complete is Relational Algebra, the theoretical basis behind SQL as described in Codd's paper A relational model for large shared data banks. Relational Algebra has the property of Godel Completeness, which means that it can express any computation that can be defined in terms of first-order predicate calculus (i.e. ordinary logical expressions). However, it is not Turing-Complete as it cannot express an arbitrary algorithmic computation.
Note that most if not all all practical SQL dialects extend the pure relational model with procedural constructs to the extent that they are Turing Complete by the definition as normally applied to programming languages. However, an individual SQL query by and large is not.
Some more egregious examples of Turing Complete domain-specific languages are TeX and sendmail.cf,. In the latter case there is actually a famous-ish example of someone using sendmail.cf to implement a universal Turing Machine simulator.
Solution 3:
If you can write a Brainf$&# interpreter in your language, it is Turing-complete. LOLCODE was proved to be Turing-complete in exactly this way.
Solution 4:
Examples of languages that are not Turing-complete frequently have bounded loops, like:
for i=1 to N {...}
but lack unbounded loops which check a more general condition, like:
while bool_expr {...}
If all possible looping constructs are bounded, your program is guaranteed to terminate. And, although an unconditional termination guarantee is potentially useful, it is also an indication that the language is not Turing-complete.
Note also that nailing down all possible looping constructs can be difficult; e.g., I'm pretty sure C++ templates were not intended to be Turing-complete...
Solution 5:
I'm not sure if there's a "minimum set of features", but to prove that a language is Turing complete, you only have to prove that it can emulate another Turing complete system (not necessarily a Turing machine), as long as the other system is known to be Turing complete. http://en.wikipedia.org/wiki/Turing_complete#Examples has a whole list of Turing complete systems. Some of them are simpler than Turing machines.