简体   繁体   中英

Why does intelliJ freeze when two classes subclasses each other?

I was wondering what will happen if two classes subclass one another, and I tried it out with Scala using IntelliJ IDEA. The implementation have no errors, but the minute I uncomment out the line inside the test object, the IDE just freezes up and theres nothing I can do. What is really happening here?

class Shoe extends Table {

}

class Table extends Shoe {

}

object test {
    // val shoe = new Shoe()
}

Seems like your version of the IDE is trying to resolve the class structure of your code to identify errors early and/or provide in-scope autocomplete suggestions. But it doesn't seem to have a condition to stop following/identify a recursive subclass.

Make sure to update to the latest version and if that doesn't fix this, file a bug report. Until then, there is probably a setting you can disable in the IDE so it won't freeze trying to resolve the circular class dependency. Corrections and suggestions may lose some accuracy or be completely disabled when you change the autocomplete settings, but it will allow you to run/compile the code to identify the error (a cyclical class dependency) and fix it.


A cyclical class dependency is when multiple classes inherit from eachother in a loop. For example, if we have two classes, class A and class B , we can create a circular dependency loop as shown in this pseudocode:

class A inherits B;
class B inherits A;

When many compilers or interpreters evaluate this, they see the first line and try to load B . To load B , they go to its declaration in line 2. Then they see that A needs to be loaded. Here, a smart compiler or interpreter will flip a table because it already knows it tried and failed to load A . A naive one will happily follow the instructions.

load B!
load A!
load B!
load A!
load B!
load A!

The smartest compilers and interpreters actually can load a circular class dependency and create code that works. But these ones are extraordinarily rare. As a programmer, sometimes it is absolutely essential to have a circular class dependency in languages without this ability.

This is where the idea of class composition comes in. Rather than inheriting a superclass, you can give a working copy of B to class A in the form of a variable.

Another great option in some cases is to provide a conversion function, allowing B to become class A ; if they both inherit from eachother, it's very likely that they contain the same data despite their different behaviours! Some languages have the built-in ability to do this conversion. The simplest example is a 'typecast'. Some languages also generalize this conversion into parametric polymorphism, where you can write a function that will work on any compatible types without needing to convert them first.


Introducing a deviously hard to parse code is always a great way to catch bugs in compilers and interpreters. So keep this snippet in mind for when you have to write and test one!

In some languages stuff like this is, rather than a bug, considered to be Undefined Behaviour. You don't want to mess with Undefined Behaviour in any code you will rely on.

Nothing, the compiler rejects this code:

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Shoe extends Table {}
class Table extends Shoe {}

// Exiting paste mode, now interpreting.

<pastie>:15: error: illegal cyclic reference involving class Shoe
       class Table extends Shoe {
                   ^

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM