
Non-terminating compilation in Java - DanielRibeiro
https://gist.github.com/1387113
======
trurl
For what it is worth, the equivalent Scala code is

    
    
      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]();

~~~
trurl
However, if you set the symbol locking depth larger (-Yrecursion n) you'll
also get a stack overflow as well. So it isn't necessarily that Scala has an
algorithmically better approach to subtyping. The symbol locking algorithm is
more of a catchall...

------
rayiner
Non-terminating compilation in Common Lisp:

    
    
        (defmacro get-stuck (x) 
            (labels ((infinite () (infinite))) 
                (infinite) x))
        (get-stuck 3)

~~~
derleth
And you can do precisely the same thing in C++ if you're willing to write
somewhat non-trivial template code.

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.)

~~~
exDM69
"And you can do precisely the same thing in C++ if you're willing to write
somewhat non-trivial template code."

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.

------
dill_day
See also: Taming Wildcards in Java's Type System
[http://cseweb.ucsd.edu/~rtate/publications/tamewild/tamewild...](http://cseweb.ucsd.edu/~rtate/publications/tamewild/tamewild-
tate-pldi11.pdf) (Section 3 Non-Termination in Subtyping)

------
lell
Anyone have a non-terminating C compile? (Other than X11. I compiled that from
scratch back in ancient times and it took a whole day. At least it seemed like
it wasn't going to terminate.)

~~~
machrider
C doesn't support metaprogramming, unless you count the preprocessor language.
With the preprocessor, you could have a couple files mutually #include each
other...

~~~
ars
I tried it:

    
    
        error: #include nested too deeply

------
finnw
Looks like a missing "occurs check."
<http://en.wikipedia.org/wiki/Occurs_check>

If so, it should be a relatively easy fix.

~~~
DanielRibeiro
Actually seems to be a bit more involved: according to the submitter[1] Java
is trying to prove something that is undecidable on Java's current type
system. To solve it you'd have to make it stricter.

[1]
[http://www.reddit.com/r/programming/comments/mlbna/scala_fee...](http://www.reddit.com/r/programming/comments/mlbna/scala_feels_like_ejb_2/c31zdbd)

------
lurker17
Looks like it terminated.

~~~
spectre
while the compilation does technically terminate it is doing so with a
StackOverflowError which along with the resulting stack-trace most likely
indicates a non-terminating recursion.

It only terminates due to a finite limit on the size of the stack.

~~~
gujk
Stack depth limits avoid some non-termination by changing them into crashes.
It is still a failure, of course, but a bit different and generally less
troublesome than say, a tailcall eliminating recursion that actually spins for
hours until a human notices and interrupts it.

------
kamkha
Here's a block of code that will cause most versions of the Java compiler to
hang _that doesn't use loops or templates_ :

    
    
      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...](http://www.exploringbinary.com/a-closer-look-at-the-
java-2-2250738585072012e-308-bug/): 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.

------
cgag
My understanding of java generics is pretty weak, could someone break this
down?

~~~
dekz
Essentially a cyclic reference between an interface and a class exploited with
generics.

------
kodablah
Happens w/ JDT in Eclipse too. Just paste it in a Java file and watch the
incremental compiler break.

------
malkia
// Windows

#include "aux"

#include "con"

// And off course

#include __FILE__

------
dodedo
Here's a non-terminating compilation in Perl:

perl -wle'BEGIN {1 while 1}'

Heh.

~~~
pyre
I'm confused. How does the begin block execute prior to compilation?

~~~
skimbrel
Begin blocks execute _during_ compilation, immediately after they've been
parsed. They're compiled themselves, and execute within the Perl interpreter
before it finishes compiling the rest of the containing module. So they don't
really execute prior to _all_ compilation, but they execute prior to the
compilation of anything sequentially after them in the source.

~~~
ars
So that isn't really non-terminating compilation, but rather non-terminating
execution?

~~~
ekiru
It's non-terminating execution during compilation, similar to the example
elsewhere in the comments using nonterminating macro definitions in Common
Lisp.

A compilation process that involves executing and waiting for the termination
of a program that doesn't terminate can't itself terminate.

------
michaelfeathers
Well deserved.

------
DrJokepu
While I would never miss a chance to bash Java, it really looks like it's just
a bug in the compiler. The input that triggers it is definitely not code that
you see in production every day. I'm sure that it will be fixed eventually.

~~~
kmm
This looks like a self-referential issue. If anything, it's a bug in
mathematics.

~~~
skrebbel
> If anything, it's a bug in mathematics.

I heard the next release will fix that.

~~~
agentgt
With the myriad unprovable universe theories (GUT) that are coming out
anything is possible :)

