Scala Tuple type inference in Java - java

This is probably a very noobish question, but I was playing a bit with Scala/Java interaction, and was wondering how well did Tuples play along.
Now, I know that the (Type1, Type2) syntax is merely syntactic sugar for Tuple2<Type1, Type2>, and so, when calling a Scala method that returns a Tuple2 in a plain Java class, I was expecting to get a return type of Tuple2<Type1, Type2>
For clarity, my Scala code:
def testTuple:(Int,Int) = (0,1)
Java code:
Tuple2<Object,Object> objectObjectTuple2 = Test.testTuple();
It seems the compiler expects this to be of parameterized types <Object,Object>, instead of, in my case, <Integer,Integer> (this is what I was expecting, at least).
Is my thinking deeply flawed and is there a perfectly reasonable explanation for this?
OR
Is there a problem in my Scala code, and there's a way of being more... explicit, in the cases that I know will provide an API for Java code?
OR
Is this simply a limitation?

Int is Scala's integer type, which is a value class, so it gets special treatment. It is different from java.lang.Integer. You can specify java.lang.Integer specifically if that's what you need.
[dlee#dlee-mac scala]$ cat SomeClass.scala
class SomeClass {
def testIntTuple: (Int, Int) = (0, 1)
def testIntegerTuple: (java.lang.Integer, java.lang.Integer) = (0, 1)
}
[dlee#dlee-mac scala]$ javap SomeClass
Compiled from "SomeClass.scala"
public class SomeClass implements scala.ScalaObject {
public scala.Tuple2<java.lang.Object, java.lang.Object> testIntTuple();
public scala.Tuple2<java.lang.Integer, java.lang.Integer> testIntegerTuple();
public SomeClass();
}

Related

Use generic type of one object as type information for another in Java

I have a class of type
IDType<IDDataType>
and another class of type
SelectionManager<IDDataType>
Is there a way that I can infer the data type for objects of the second class by passing an instance of the first one? Something like that
IDType<String> idType = new IDType<String>();
SelectionManager<idType.getGenericType()> selectionManager = new Se.....
Of course, the reason I want to do this is that idType (String is an example here) is created in totally unrelated places.
There is no elegant way in java to do something like:
IDType<String> idType = new IDType<String>();
idType.getGenericType();
This is because the Java compiler does not know the type of the object at runtime. Read the part about "Type erasure" on the wikipedia page of "Generics in Java". Java was initially not designed to work with these.
You could always use some dirty hacks though ... instanceof can do the job but that is ugly programming.
You can declare extra generics in each methods.
public <T> void method() {
IDType<T> idType = new IDType<T>();
SelectionManager<T> selectionManager = new SelectionManager<T>();
Your problem is a bit hard to understand in the way that you have written the example because you want someone who calls your code to define the Types but that is not how your example is written.
As the code is at the moment you could make it non-generic and it would make no difference because at compile time your code has all the type information.
For your example to work there has to be a code snippet A (written by someone else) where an IDType is defined and then passed to the code you have written (snippet B):
IDType<String> idType = new IDType<String>();
YourClass.yourMethod(idType);
Snippet B (your code) would then look something like this:
public <T> void yourMethod(IDType<T> idType){
SelectionManager<T> selectionManager = new SelectionManager<T>();
}
This means that selectionManager would have the same genericType as idType.
Hope this makes sense!

Java Generics, support "Specialization"? Conceptual similarities to C++ Templates?

I know quite a bit how to use C++-Templates -- not an expert, mind you. With Java Generics (and Scala, for that matter), I have my diffuculties. Maybe, because I try to translate my C++ knowledge to the Java world. I read elsewhere, "they are nothing alike: Java Generics are only syntactic sugar saving casts, C++ Templates are only a glorified Preprocessor" :-)
I am quite sure, both is a bit simplified a view. So, to understand the big and the subtle differences, I try to start with Specialization:
In C++ I can design a Template (class of function) that acts on any type T that supports my required operations:
template<typename T>
T plus(T a, T b) { return a.add(b); }
This now potentially adds the plus() operation to any type that can add().[note1][1]
Thus, if T supports the add(T) my template woll work. If it doesn't,
The compiler will not complain as long as I do not use plus(). In Python
we call this "duck typing": *If it acts like a duck, quacks like a duck,
it is a duck.* (Of course, with using type_traits this is modified a bit,
but as long as we have no concepts, this is how C++ Templates work, right?)
I guess, thats how Generics in Java work as well, isn't it? The generic type I device is used as a "template" how to operate on any anything I try to put in there, right? As far as I understand I can (or must?) put some constraints on the type arguments: If I want to use add in my template, I have to declare the type argument to implement Addable. Correct? So, no "duck typing" (for better or worse).
Now, in C++ I can choose to specialize on a type that has no add():
template<>
T plus<MyX>(MyX a, MyX b) { return a + b; }
And even if all other types still can use the "default" implementation, now I added a special one for MyX -- with no runtime overhead.
Is there any Java Generics mechanism that has the same purpose? Of course, in programming everything is doable, but I mean conceptually, without any tricks and magic?
No, generics in Java don't work this way.
With generics you can't do anything which would not be possible without Generics - you just avoid to have to write lots of casts, and the compiler ensures that everything is typesafe (as long as you don't get some warnings or suppress those).
So, for each type variable you can only call the methods defined in its bounds (no duck typing).
Also, there is no code generation (apart from some adapter methods to delegate to methods with other parameter types for the purpose of implementing generic types). Assume you had something like this
/**
* interface for objects who allow adding some other objects
*/
interface Addable<T> {
/** returns the sum of this object and another object. */
T plus(T summand);
}
Then we could create our sum method with two arguments:
public static <T extends Addable<T>> T sum(T first, T second) {
return first.plus(second);
}
The static method is compiled to the same bytecode like this (with additional type information in annotations):
public static Addable sum(Addable first, Addable second) {
return first.plus(second);
}
This is called type erasure.
Now this method can be called for every pair of two elements of an addable type, like this one:
public class Integer implements Addable<Integer> {
public Integer plus(Integer that) {
return new Integer(this.value + that.value);
}
// private implementation details omitted
}
What here happens is that the compiler creates an additional synthetic method like this:
public Object plus(Object that) {
return this.plus((Integer)that);
}
This method will only be called by generic code with the right types, this guarantees the compiler, assuming you are not doing some unsafe casts somewhere - then the (Integer) cast here will catch the mistake (and throw a ClassCastException).
The sum method now always calls the plus method of the first object, there is no way around this. There is not code generated for every type argument possible (this is the key difference between Java generics and C++ templates), so we can't simply replace one of the generated method with a specialized one.
Of course, you can create a second sum method like irreputable proposed (with overloading), but this will only be selected if you use the MyX type directly in source code, not when you are calling the sum method from some other generic code which happens to be parametrized with MyX, like this:
public static <T extends Addable<T>> product (int times, T factor) {
T result = factor;
while(n > 1) {
result = sum(result, factor);
}
return result;
}
Now product(5, new MyX(...)) will call our sum(T,T) method (which in turn calls the plus method), not any overloaded sum(MyX, MyX) method.
(JDK 7 adds a new dynamic method dispatch mode which allows specialization by every argument on run time, but this is not used by the Java language, only intended to be used by other JVM-based languages.)
no - but your particular problem is more of an overloading issue.
There's no problem to define 2 plus methods like these
<T extends Addable>
T plus(T a, T b) { .. }
MyX plus(MyX a, MyX b) { .. }
This works even if MyX is an Addable; javac knows that the 2nd plus is more specific than the 1st plus, so when you call plus with two MyX args, the 2nd plus is chosen. In a sense Java does allow "specialized" version of methods:
f(T1, T2, .. Tn)
f(S1, S2, .. Sn)
works great if each Si is a subtype of Ti
For generic classes, we can do
class C<T extends Number> { ... }
class C_Integer extends C<Integer>{ ... }
caller must use C_Integer instead of C<Integer> to pick the "specialized" version.
On duck typing: Java is more strict in static typing - unless it is a Duck, it is not a duck.
HI,
java Generics it's different from C++ template.
Example:
Java code:
public <T> T sum(T a, T b) {
T newValue = a.sum(b);
return newValue;
}
In java this code don't work because generics base is class java.lang.Object, so you can use only method of this class.
you can construct this methis like this:
public <T extends Number> T sum(T a, T b) {
T newValue = a.sum(b);
return newValue;
}
in this case the base of generics is class java.lang.Number so you can use Integer, Double, Long ecc..
method "sum" depend of implementation of java.lang.Number.
Bye

Java enums and generics

This thing is troubling me for a while now. I have asked questions before, but probably with a bad phrasing and an example that was too abstract. So it wasn't clear what I was actually asking. I'll try again. And please don't jump to conclusions. I expect that the question is not easy at all to answer!
why can't I have an enum with generic type parameters in Java?
The question is not about why it's not possible, syntactically. I know it's just not supported. The question is: why did the JSR people "forget" or "omit" this very useful feature? I can't imagine a compiler-related reason, why it wouldn't be feasible.
Here's what I would love to do. This is possible in Java. It's the Java 1.4 way to create typesafe enums:
// A model class for SQL data types and their mapping to Java types
public class DataType<T> implements Serializable, Comparable<DataType<T>> {
private final String name;
private final Class<T> type;
public static final DataType<Integer> INT = new DataType<Integer>("int", Integer.class);
public static final DataType<Integer> INT4 = new DataType<Integer>("int4", Integer.class);
public static final DataType<Integer> INTEGER = new DataType<Integer>("integer", Integer.class);
public static final DataType<Long> BIGINT = new DataType<Long> ("bigint", Long.class);
private DataType(String name, Class<T> type) {
this.name = name;
this.type = type;
}
// Returns T. I find this often very useful!
public T parse(String string) throws Exception {
// [...]
}
// Check this out. Advanced generics:
public T[] parseArray(String string) throws Exception {
// [...]
}
// Even more advanced:
public DataType<T[]> getArrayType() {
// [...]
}
// [ ... more methods ... ]
}
And then, you could use <T> in many other places
public class Utility {
// Generic methods...
public static <T> T doStuff(DataType<T> type) {
// [...]
}
}
But these things are not possible with an enum:
// This can't be done
public enum DataType<T> {
// Neither can this...
INT<Integer>("int", Integer.class),
INT4<Integer>("int4", Integer.class),
// [...]
}
Now, as I said. I know these things have been designed exactly that way. enum is syntactic sugar. So are generics. Actually, the compiler does all the work and transforms enums into subclasses of java.lang.Enum and generics into casts and synthetic methods.
but why can't the compiler go further and allow for generic enums??
EDIT:
This is what I would expect as compiler-generated Java code:
public class DataType<T> extends Enum<DataType<?>> {
// [...]
}
I'm going to guess a bit and say that it is because of covariance issues on the type parameter of the Enum class itself, which is defined as Enum<E extends Enum<E>>, although it is a bit much to investigate all the corner cases of that.
Besides that, a primary use case of enums is with things like EnumSet and valueOf where you have a collection of things with different generic parameters and get the value from a string, all of which would not support or worse the generic parameter on the enum itself.
I know I'm always in a world of pain when I try to get that fancy with Generics, and I imagine the language designers peeked at that abyss and decided to not go there, especially since the features were developed concurrently, which would mean even more uncertainty for the Enum side of things.
Or put another way, it would have all the problems of Class<T> in dealing with classes which themselves have generic parameters, and you would have to do a lot of casting and dealing with raw types. Not truly something that the language designers felt was worth it for the type of use case you are looking at.
EDIT: In response to the comments (and Tom - a downvote?), nested generic parameter makes all kinds of bad things happen. Enum implements Comparable. That simply would not work to compare two arbitrary elements of the enum in client code if generics were in play. Once you deal with a Generic parameter of a Generic parameter, you end up with all kinds of bounds problems and headaches. It is hard to design a class that handles it well. In the case of comparable, I could not figure out a way to make it work to compare two arbitrary members of an enum without reverting to raw types and getting a compiler warning. Could you?
Actually the above is embarrassingly wrong, as I was using the DataType in the question as my template for thinking about this, but in fact an Enum would have a subclass, so that isn't quite right.
However, I stand by the gist of my answer. Tom brought up EnumSet.complementOf and of course we still have valueOf that produces problems, and to the degree that the design of Enum could have worked, we have to realize that that is a 20/20 hindsight thing. Enum was being designed concurrently with generics and didn't have the benefit of validating all such corner cases. Especially considering that the use case for an Enum with a generic parameter is rather limited. (But then again, so is the use case for EnumSet).
I don't think it is impossible to have generified enum. If you could hack into compiler, you can have a subclass of Enum that is generic, and the class file of your generic enum wouldn't cause problems.
But in the end, enum is pretty much a syntax sugar. In C, C++, C#, enums are basically alias for int constants. Java gives it more power, but it is still supposed to represent simple items.
Somewhere people have to draw the line. Just because a class has enumerated instances, doesn't mean it must be an enum. If it is sophisticated enough in other areas, it deserves to be a regular class.
In your case, there is not much advantage to make DataType an enum. You can use enum in switch-case, that's about it, big deal. The non-enum verion of DataType works just fine.
This is how I think of it -
Regular classes have instances. You create a new instance of a class use it for some purpose and then dispose it. For example List<String> is a list of strings. I can do what ever I want to do with strings and then when I am done I can later do the same functionality with integers.
To me enumerators are not types that you create instances of. Its same thing as a singleton. So I can see why JAVA wouldn't allow generics for Enums because you really can't create a new instance of type Enum to use temporary like you do with classes. Enums are supposed to be static and only have one instance globally. To me, it wouldn't make sense to allow generics for a class that only has one instance globally.
I hope this helps.
I think that the reason why you wish to parameterize the enum with <T> boils down to being able to have different method signatures for the various constants of the enum.
In your example, the signature (type of parameters and return type) for parse would be:
for Datatype.INT: int parse(String)
for Datatype.VARCHAR: String parse(String)
and so on
So how would the compiler be able to typecheck something like:
Datatype type = ...
...
int x = type.parse("45");
???
To apply static typing and typechecking to this kind of expression, the signature of the method must be the same for all the instances. However, in the end you suggest to have different method signatures for different instances... That's why it's not possible to do it in Java.
public enum GenericEnum<T> {
SIMPLE, COMPLEX;
public T parse(String s) {
return T.parse(s);
}
}
public void doSomething() {
GenericEnum<Long> longGE = GenericEnum<Long>.SIMPLE;
GenericEnum<Integer> intGE = GenericEnum<Integer>.SIMPLE;
List<Long> longList = new LinkedList<Long>();
List<Integer> intList = new LinkedList<Integer>();
assert(longGE == intGE); // 16
assert(stringList.equals(intList)); // 17
Object x = longGE.parse("1"); // 19
}
The asserts at line 16 and 17 are both true. The generic types are not available at run time.
One of the advantages of an enum is that you can use == to compare them. The assert at line 16 will evaluate to true.
At line 19 we run into a problem though. longGE and intGE are the same object (as the assert at line 16 shows.) What will be returned by the parse("1")? The generic type information is not available at run time. So there would be no way to determine T for the parse method at run time.
Enums are basically static, they only exist once. And it doesn't make sense to apply generic typing to static types.
I hope this helps.
Note - this is not meant to be working code. It is using the syntax suggested in the original question.

Calling Java vararg method from Scala with primitives

I have the following code in Java:
public class JavaClass {
public static void method( Object x ) {
}
public static void varargsMethod( Object... x ) {
}
}
When I try and access it from Scala,
object FooUser {
JavaClass.method(true)
JavaClass.varargsMethod(true) // <-- compile error
}
I get the following compile error:
type mismatch; found : Boolean(true) required: java.lang.Object Note: primitive types are not implicitly converted to AnyRef. You can safely force boxing by casting x.asInstanceOf[AnyRef]
The error message is very helpful and shows how to fix the error, but I was wondering why the compiler is (apparently) happy to implicitly convert a scala.Boolean in one method call but not the other. Is this a bug or intentional?
Updated to add:
I'm using Scala 2.8. If I make the varargsMethod signature
public static <T> void varargsMethod(T... xs) {
instead, then the error also goes away. I'm still puzzled as to why the compiler can't figure it out.
Scala varargs and Java varargs are different. You need to do a conversion:
def g(x: Any*) = x.asInstanceOf[scala.runtime.BoxedObjectArray]
.unbox(x.getClass)
.asInstanceOf[Array[Object]]
...
JavaClass.varargsMethod(g(true))
or (in 2.8.0+)
JavaClass.varargsMethod(java.util.Arrays.asList(true))
Since scala.Boolean is a subclass of scala.AnyVal but not scala.AnyRef (translated to java.lang.Object), a Boolean cannot be passed to a method expecting Object(s).
You can use the companion object scala.Boolean to "box" (in Java's sense, of course) a boolean into java.lang.Boolean:
JavaClass.varargsMethod(Boolean.box(true))
The other AnyVal classes have corresponding box methods (e.g. Int.box). There are also unbox methods to do the opposite.
A more complicated use case:
JavaClass.varargsMethod(Seq(1, 2, 3, 4).map(Int.box): _*) // passes 1, 2, 3, 4
I don't know when these were added to the standard library, but with these you don't have to use the implementation classes of scala.runtime.*.
Note, with Scala version 2.13.x, this works out-of-the-box (no pun) without having to manually box the value.
Probably can file a bug about it. It seems like it should throw an exception in both cases or neither. Not sure it's something that will ever be fixed as it probably is caused by some cleverness in the implementation of varargs that prevents the boxing from taking place.

Non-generic reference to generic class results in non-generic return types

I have a legacy class that the class itself is not a generic but one of its methods return type uses generics:
public class Thing {
public Collection<String> getStuff() { ... }
}
getStuff() uses generics to return a collection of strings. Therefore I can iterate over getStuff() and there's no need to cast the elements to a String:
Thing t = new Thing();
for (String s: t.getStuff()) // valid
{ ... }
However, if I change Thing itself to be a generic but keep everything else the same:
public class Thing<T> {
public Collection<String> getStuff() { ... }
}
and then keep using the non-generic reference to Thing, getStuff() no longer returns Collection<String> and instead returns a non-typed Collection. Thus the client code does not compile:
Thing t = new Thing();
for (String s: t.getStuff()) // compiler complains that Object can't be cast to String
{ ... }
Why is this? What are the workarounds?
My guess is that by using a non-generic reference to a generic class, Java turns off all generics for the entire class. This is pain, because now I've broken my client code by making Thing a generic.
Edit: I'm making Thing generic for another method which is not listed in the above example code. My question is educational as to why the above cannot be done.
Ok, take two, I misunderstood your question.
When you delcare Thing (this is called a raw type) instead of Thing<?> (parameterized type) the Java compiler strips out all generic arguments, even thogh (as in your case) the generic type of the method has nothing to do with the generic type of the class.
From the (excellent) Java Generics FAQ:
Can I use a raw type like any other type?
Methods or constructors of a raw type have the signature that they would have after type erasure.
This seemingly inocuous and unobtrusive sentence describes the behaviour in question. You're using Thing as a raw type so the return type is Collection (not Collection<String>) since this is the type after type erasure.
Confused? Not surprising. Just look at the size of that FAQ. There's probably about three people on earth who nderstand the full implications of Java Generics. Just consider my favourite declaration from the JDK:
Enum<T extends Enum<T>>
(Theres an explanation of that in the FAQ too).
It is failing because of erasure. You can read more about it in these Java Tutorials
I think this is totally normal. In my opinion using Thing t = new Thing(); for generic enabled class is totally a mistake. When compiler see a generic class used as a class without type parameter, it think it must erase all generic types from that class. This is how you can compile old codes without use of generics in new java compilers and compiler let that old codes use generic enabled classes (e.g. java.util.ArrayList) without any problem. (and this is how java not need separated System.Collection.Generic.List and System.Collection.List like C#). You can run Thing t = new Thing(); with adding a simple type parameter on it, Thing<Object> t = new Thing<Object>();, only thing java compiler needs is making sure that you are using java generic consciously. I never can blame Java for its great backward compatibility.
I know I am a bit late :D

Categories

Resources