This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 258738 - 'instanceof' completion hints should consider type of variable to narrow the list of suggestions
Summary: 'instanceof' completion hints should consider type of variable to narrow the ...
Status: NEW
Alias: None
Product: java
Classification: Unclassified
Component: Editor (show other bugs)
Version: 8.0.2
Hardware: PC Windows 7
: P3 normal (vote)
Assignee: Dusan Balek
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-04-08 20:24 UTC by tln
Modified: 2016-04-15 15:16 UTC (History)
1 user (show)

See Also:
Issue Type: ENHANCEMENT
Exception Reporter:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description tln 2016-04-08 20:24:56 UTC
When I type
if (var instanceof 
and hit Ctrl+Space, I get a list of suggestions.

This list of suggestions currently contains all known classes.
Instead it should only list the type of variable var and subclasses of that type.
Upon hitting Ctrl+Space a second time all classes should be offered.

Example:

Collection var;
if (var instanceof [Ctrl+Space]

Hints here should include Collection, List, Set, and so on, but not String.

The current labelling of the suggestion list reads "Imported Items". Not sure what it's supposed to mean, but it's definitely not the list of imports defined in the current file.
Comment 1 Svata Dedic 2016-04-11 06:38:09 UTC
You luckily picked up String class ;) as an example - you are right that String should not be offered; not because it does not implement Collection - this property alone is not sufficient to exclude a class from list of completion offerings.

Suppose that you have an inhertance chain:

AbstractHolder -> FooHolder implements Collection
               -> BarHolder implements Collection

then let's have 

Collection var = ....;

if (var instanceof |

AbstractHolder could be also offered in CC at | position -- although it does not implement Collection itself, some (all) of its subclasses do. String in your example is final class, so it can have no subclasses that could eventually satisfy the instanceof check. The exclusion filter will be quite elaborate for non-final classes.

Passing to java cc owner.
Comment 2 tln 2016-04-11 12:47:15 UTC
You are right, this is a case I hadn't considered.

So let's rephrase the problem scenario. The only two cases that you can safely exclude from the list of suggestions are the following:
1. var is of class type V, and a potential suggestion is of another class type S that has no line of inheritance from V.
2. One of var and the suggestion is of an interface type, the other one is of a final class type that does not implement the interface.

These two rules allow for some narrowing on the list of suggestions, but the vast majority of classes and interfaces would still have to be offered in most cases. So I'd agree that just looking at this wouldn't justify to change anything.

Nevertheless, looking at it from the other end I still think it's worth a second thought. instanceof as such is usually a sign of bad design, so it's not used very often. And in the few cases where I need it or use it, I'm usually dealing with a direct line of inheritance.

To verify how other developers use it I searched the JDK source code and found about 6300 uses of instanceof. I checked about 50 random samples from those from across the whole source code and although I didn't count explicitely, I'd say the following figures just from my gut feeling:
- 50% are instanceof on java.lang.Object.
- 40% are instanceof in another direct line of inheritance (Collection types to more specific collection types, Stream types to more specific stream types, Writer types to more specific writer types, Node types to more specific node types, Task types to more specific task types, Model types to more specific model types, not to forget Exception types to more specific exception types etc.). This finding includes both classes and interfaces.
- <10% are cases as you mentioned them. Just to tell an example:
java.util.concurrent.ForkJoinTask has a method that starts like this:
public static <T extends ForkJoinTask<?>> Collection<T> invokeAll(Collection<T> tasks) {
    if (!(tasks instanceof RandomAccess) || !(tasks instanceof List<?>)) {

From my own experience with my own code it's the same distribution or even considerably less of the first and the third case. I have an aversion against doing instanceof checks outside direct inheritance, because I feel hardly anything indicates bad design more clearly. First you use a type-safe language like Java, and then you can't handle it or don't go the whole way. instanceof is not just ugly but using it outside lines of inheritance makes it really hard to read too.
The first case (java.lang.Object) on the other hand is important on the level of the java language libraries, but outside them you don't use java.lang.Object often anyway. I only use it for synchronization objects actually. So I really think a typical developer will do more than 70% of his instanceof checks in direct lines of inheritance.

Having said this I feel that the following approach is worth discussing:
- If var is of type java.lang.Object, offer all classes and interfaces (you might exclude java.lang.Object itself, but this detail is not worth bothering).
- If var is another type, offer only sub-classes (or sub-interfaces and implementing classes).
- If user hits Ctrl+Space again, offer everything.

I really feel that in those >40% of the cases in the "real" world this would really make things easier, because usually the list of options would fit in the suggestion box without scrolling. This noteworthy simplification would clearly justify another Ctrl+Space for the <10% of the cases where you need something "exotic" which doesn't share a direct line of inheritance. (It would also help you reconsider if this really has to be.)

Seeing the fact that instanceof is more a compromise with sloppy programming practises than a clean language feature that you should actually use frequently I could also accept it if you didn't want to change anything and always offer the full list of suggestions.
Comment 3 markiewb 2016-04-15 15:16:41 UTC
(In reply to Svata Dedic from comment #1)
> You luckily picked up String class ;) as an example - you are right that
> String should not be offered; not because it does not implement Collection -
> this property alone is not sufficient to exclude a class from list of
> completion offerings.
> 
> Suppose that you have an inhertance chain:
> 
> AbstractHolder -> FooHolder implements Collection
>                -> BarHolder implements Collection
> 
> then let's have 
> 
> Collection var = ....;
> 
> if (var instanceof |
> 
> AbstractHolder could be also offered in CC at | position -- although it does
> not implement Collection itself, some (all) of its subclasses do. String in
> your example is final class, so it can have no subclasses that could
> eventually satisfy the instanceof check. The exclusion filter will be quite
> elaborate for non-final classes.
> 
> Passing to java cc owner.

@Svata: I don't understand. It does not explain (for me), why f.e. java.lang.Number or java.lang.Thread (non-final classes) are displayed in CC.