Non-terminating compilation in Java
gist.github.com
gist.github.com
trait Pong[T] {}
class Ping[T] extends Pong[Pong[X forSome { type X >: Ping[Ping[T]]}]] {
def Ping() {
val Ping : Pong[X forSome { type X >: Ping[Long]}] = new Ping[Long]();
}
}
which produces the errors Test.scala:3: error: illegal cyclic reference involving class Ping
class Ping[T] extends Pong[Pong[X forSome { type X >: Ping[Ping[T]]}]] {
^
Test.scala:5: error: type mismatch;
found : Ping[Long]
required: Pong[X forSome { type X >: Ping[Long] }]
Note: Long <: X forSome { type X >: Ping[Long] }, but trait Pong is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
val Ping : Pong[X forSome { type X >: Ping[Long]}] = new Ping[Long](); (defmacro get-stuck (x)
(labels ((infinite () (infinite)))
(infinite) x))
(get-stuck 3) #.(loop)This kind of thing is more surprising to Java programmers, I daresay, because the idea compiling a program being Turing-complete is not covered in most Java programming courses.
(Problems are Turing-complete; languages are Turing-equivalent, if you ignore the fact the Universe is finite.)
https://gist.github.com/1388217
Crashes clang, reaches maximal template depth in g++. Seems there is no tail call optimization for templates ;).
The template code required to cause non-termination in template instantiation is a very trivial infinite loop.
Simple metaprogramming with templates is not very hard, it's kind of like doing lisp with template parameters. Variadic templates (in c++11) make this a whole lot simpler.
error: #include nested too deeplyIf it was left uninitialized, it would've simply reserve space for it, but won't allocate anything in memory (compiler memory), and then the linker is just going to increase the BSS section (uninitialized data) with it's size.
Later the program may or may not run. Some systems might allow many gigabytes of uninitialized data. Others simply won't.
If so, it should be a relatively easy fix.
[1] http://www.reddit.com/r/programming/comments/mlbna/scala_fee...
I don't see a problem with non-terminating compilation. It makes sense to add more power to the compiler, but it comes at a cost. The possibility of non-termination is not a huge price to pay for it. In practice, the recursion will never go very deep so a simple max recursion depth check is enough to keep the compiler from hogging cpu and memory.
It only terminates due to a finite limit on the size of the stack.
class compilehang {
public static void main(String[] args) {
double d = 2.2250738585072012e-308;
System.out.println("Value: " + d);
}
}
From http://www.exploringbinary.com/a-closer-look-at-the-java-2-2...: apparently the constant in the code above causes Java's double value correction loop to oscillate between two values, thus causing the compiler to hang.perl -wle'BEGIN {1 while 1}'
Heh.
A compilation process that involves executing and waiting for the termination of a program that doesn't terminate can't itself terminate.
Some languages don't contain instructions that can instruct the compiler to loop or recurse (C, assembly, brainfuck). Some languages contain a sub-language or meta-language which can instruct the compiler to recurse (java, C++). Some languages use their native syntax to instruct the compiler, making looping or recursion trivial (Perl, Lisp).
From the reception to my comment it seems HN readers aren't very familiar with dynamic languages. Perhaps I invited those subject to dunning-kruger by providing an overly simplified example.
#include "aux"
#include "con"
// And off course
#include __FILE__
I heard the next release will fix that.