• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Paul Clapham
  • Jeanne Boyarsky
  • Bear Bibeault
Sheriffs:
  • Rob Spoor
  • Henry Wong
  • Liutauras Vilda
Saloon Keepers:
  • Tim Moores
  • Carey Brown
  • Stephan van Hulst
  • Tim Holloway
  • Piet Souris
Bartenders:
  • Frits Walraven
  • Himai Minh
  • Jj Roberts

'one-sided' generics?

 
Greenhorn
Posts: 10
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Looking at the following code:

1.

2.


it seems like from 1. we have:
A: ObjectInstance<Type> o = new ObjectInstance(); is treated like ObjectInstance<Type> o = new ObjectInstance<Type>();
And from 2. we have:
B: ObjectInstance o = new ObjectInstance<Type>(); is treated like ObjectInstance o = new ObjectInstance();

But then I saw some other question which breaks these rules:


in this case, I would've thought that line * follows rule B, but if that were the case, then it would be
Predicate p = Predicate(), which then should cause * to NOT COMPILE as it does not implement
public boolean test(Object o)
But it does compile ok...

Can someone confirm whether my interpretation of A and B are even correct and if not, are there some rules to follow with this kind of thing?

 
Master Rancher
Posts: 3827
50
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jay Chung wrote:in this case, I would've thought that line * follows rule B, but if that were the case, then it would be
Predicate p = Predicate(), which then should cause * to NOT COMPILE as it does not implement
public boolean test(Object o)


Your interpretation is pretty good, but a little off.  In rule B, it's not that the compiler treats new ObjectInstance<Type>() as new ObjectInstance() for the entire statement.  Rather, it makes that substitution, ignoring the generic parameter, while evaluating the assignment part (the =).  So think of the compiler as looking at the expression in different parts.  First:

This part makes sense on its own - a CourseFilter needs to have a boolean test(String).  Great!  The compiler is happy with this.

And then this part:

When the compiler looks at the assignment, it basically asks itself, can the thing on the right be treated as the thing on the left?  Which in this case means, can a Predicate<String> be treated as a Predicate?  The answer is yes, it's willing to ignore the generic part and let the assignment take place.  If you want to treat this as a raw Predicate, you can, the compiler will let you.  However that doesn't mean it's re-evaluating the entire right hand side to make it conform to the raw Predicate type.  The right hand is still a Predicate<String>, with a test(String) method.  And the assignment is allowed to happen.

Now at run time, you may still run into problems.  What happens if you run the following?
 
Jay Chung
Greenhorn
Posts: 10
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Mike Simmons wrote:

Jay Chung wrote:in this case, I would've thought that line * follows rule B, but if that were the case, then it would be
Predicate p = Predicate(), which then should cause * to NOT COMPILE as it does not implement
public boolean test(Object o)


Your interpretation is pretty good, but a little off.  In rule B, it's not that the compiler treats new ObjectInstance<Type>() as new ObjectInstance() for the entire statement.  Rather, it makes that substitution, ignoring the generic parameter, while evaluating the assignment part (the =).  So think of the compiler as looking at the expression in different parts.  First:

This part makes sense on its own - a CourseFilter needs to have a boolean test(String).  Great!  The compiler is happy with this.

And then this part:

When the compiler looks at the assignment, it basically asks itself, can the thing on the right be treated as the thing on the left?  Which in this case means, can a Predicate<String> be treated as a Predicate?  The answer is yes, it's willing to ignore the generic part and let the assignment take place.  If you want to treat this as a raw Predicate, you can, the compiler will let you.  However that doesn't mean it's re-evaluating the entire right hand side to make it conform to the raw Predicate type.  The right hand is still a Predicate<String>, with a test(String) method.  And the assignment is allowed to happen.

Now at run time, you may still run into problems.  What happens if you run the following?



Yeah makes sense, the last print line causes exception because LHS reference type determines what method is called, in this case test(Object o) since LHS uses no generics.

I also tested the opposite:


Looks like this breaks rule A (line *) and I'm guessing it's the same reason you just outlined for the opposite way - the compiler independently checks


before independently checking


1. is that correct?

2. And so to conclude, it seems that rule A and B DO hold, except for cases when RHS is an anonymous class...
In this case, perform 2 independent checks:
-first check the anonymous class implements the superclass/interface correctly,
-then check the assignment is correct.

Would you agree with these statements? (sorry for all the questions - super stressed   )
 
Mike Simmons
Master Rancher
Posts: 3827
50
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
That's correct.  The exception isn't just for anonymous classes though - more generally, the compile doesn't figure out everything simultaneously; it figures things out in steps.  Because assignment operators are lowest in precedence, the compiler will figure out what the assignment operator does (and if any type conversion needs to happen) only after it figures out the type of the left side and the type of the right side.  Usually we don't need to isolate the individual steps when we think and talk about this, unless something complex is happening in one of the operands.

Put another way, rule A shouldn't mean, take out the generic and re-evaluate the whole expression without it.  It just means, pretend the generic isn't there, for purposes of deciding what the assignment operator does.  Your right-hand side was a Predicate<String> and the left was a Predicate, OK, so the resulting variable is a Predicate, OK.  But that does't force re-evaluation of the right hand side as a Predicate.

The other general rule is, when you mix raw types with generics, weird and confusing things happen, and so you should avoid mixing raw types with generics.  Or just avoid using raw types at all.
 
Grow a forest with seedballs and this tiny ad:
SKIP - a book about connecting industrious people with elderly land owners
https://coderanch.com/t/skip-book
reply
    Bookmark Topic Watch Topic
  • New Topic