I see similar questions asked for C++ and C# but not for Java. Is there a way I can define concrete types along with generics in a class signature? Something like this:
import java.util.Optional;
class Foo<T, Optional<O>> {
}
Compiler describes this as invalid syntax.
You're mixing up the declaration of a type variable and the usage of one.
In class Foo<T> {}, as well as public static <T> void foo() {}, the <T> part is declaring the types. It's equivalent to the x in public class Foo { int x; } - you are saying that there is a type variable and it has the name T, you're not using it.
Hence, Optional<O> is obviously illegal there. Just like int a + b is gobbledygook.
You CAN put a bound on your typevar; just like Number a doesn't just declare an a but also limits it to be a reference to some instance of Number (or null), you can do the same when you declare types: class Foo<T extends Number> puts a bound on T, decreeing that it must necessarily be Number or some subtype thereof.
Thus, in theory, you could do something like:
class Foo<T, O extends Optional<?>> {}
except that makes no sense, there's no reason to ever write that code. What is your intent? That the second typevar is optional? That doesn't work in java, unfortunately. No such thing as optional typevars.
That it can be an Optional<T>? Just T is any type, including Optional, so that isn't needed.
That it must be an Optional<T>? That's 'optional abuse'. Optional isn't type-orthogonal and thus isn't that kind of flexible. You mustn't write code that way. Optionals can make sense as the return type of a method and shouldn't be used anywhere else; parameters should never be typed that way, fields should never be typed that way, and they definitely should never show up in generics. Any code that calls a method that returns an optional should immediately 'unwrap' it (e.g. by chaining an .orElse call).
The language spec doesn't enforce it, but the language gives you zero tools to deal with optional dichotomy. Essentially that means any API or code that works that way is going to lack abstractive powers to an incredible degree, and would feel exceedingly clunky as a result.
For example, it is impossible to write a method in java that accepts either List<String>, or List<Optional<String>>, but not e.g. List<Optional<Number>>, and can operate on the provided list regardless. Eventhough that is an operation that makes perfect sense: You can trivially have a method that for example only reads from the list (never calls .add or .addAll or whatnot on the list), and when it reads, does nullchecks (which would be pointless for a list that contains never-null strings, but it doesn't harm anything). Or, the method does invoke .add, but always adds non-null things. adding a guaranteed not null string is a legal move on a 'list of never null strings' and also a legal move on 'list of could-be-null string refs', and yet, java doesn't let you write this method: That's why you shouldn't treat optional as a type-in-flight; APIs cannot deal with the dichotomy.
And yet, you can't write this in java or just about any other language that supports Optional. That's just one example, there are many, they all point to the same thing: Optional? Only sensible as return values from methods, and must be unwrapped immediately; any other usage of them is harmful and silly: Leads to bugs and code that is hard to maintain, and isn't particularly flexible (is hard to adapt to changing requirements).
Related
I was wondering if it is possible to create a construtor function:
public <C, T> C newInstance(Class<C> constructor_class,
Class<T> type,
Object...parameters){
// create a new Instance with the generic type and the paramters
//so basicly like this, but with generics and parameters
return constructor_class.newInstance();
}
You basically can't. Your example is broken - what is type supposed to represent?
Let's say you want to dynamically create a HashMap<String, Integer>. This would require that you pass in HashMap.class, String.class, and Integer.class, but we run into a TON of problems right off the bat:
How do we know that HashMap has 2 args? We don't, so you'd have to pass 2 class references via varargs and at runtime I guess we throw an exception if you passed the wrong number of classes.
What if you pass Map, which cannot be instantiated at all?
But most of all, this is completely useless, generics that do not show up in method/field/class signatures are figments of the compiler's imagination: javac uses it during compilation to warn or error, as well as to generate invisible caste operations, and then chucks this info away. By doing it dynamically, all that 'at compile time' stuff cannot work by definition (we're compiling, not running, the whole point is for the types to be dynamic, so javac cannot do), so to javac it is useless, and the info is then chucked. So that makes it fully useless, then, no?
Furthermore, Class cannot be used to convey generics args. What if I wanted a HashMap<List<String>, Integer> instead? List<String> does not exist as a class literal, so java.lang.Class<T> cannot be used here. There are also class objects (specifically, int.class) that aren't legal in generics. So, we have ?, ? super Foo, A, B extends A, C extends A & Serializable, List<String> all as examples of things that can go in <> but which cannot be a java.lang.Class reference, and int.class that is a legal class ref but which cannot go in <>. You can't put a square peg in a round hole. Let alone the fact that even if you could, it would do literally absolutely nothing whatsoever (see point #3: This is useless - most generics, and definitely the generics you'd use here, affect compilation and cease to exist afterwards).
There are crazy hacks in this space (super type tokens, for example), but if you do not fully understand how generics work under the hood, there is 0.00001% or less chance you will be able to use such hacks usefully, so don't bother until then. And asking this question, especially with that pseudocode, strongly suggests you don't understand enough of it yet.
I would like to ask if it is possible in Java 8+ to declare a generic bound T so that it extends superclass/superinterface U (which could be Object, or Serializable) but breaks compilation if T extends L (which must extend U first).
I have found this problem using filter range objects: one of my developers invoked the wrong method and spent much time questioning on why it was giving inconsistent results. So I wanted to help her changing the method signature, someway, to early detect that she is using wrong code.
I will display my example case in a very simplified way. We are talking about tables and dynamic filters.
#Displays a text "[field name] is equal to [value]"
#Value (T) must be Oject
#Internally uses Object::toString
#Null shows blank string
public static String <T> localizeEq(Localizable fieldName, T value);
<LocalDate> localize(forI18nLabel("DATE_OF_BIRTH_LABEL",dateOfBirth)
"Date of birth equals 01/01/1900" (en)
"syntymäaika on 01/01/1990" (fi)
#Additional diplays for "ge, gte, le..."
#Overload methods not displayed
#SimpleFilter is {op:"ge|ge|eq...",value:""}}
#The effective display depends on the op attribute
#Example "[field name] is [operator] [value]"
#Example "[field name] is less or equal than [upper]"
#If <filter != null but filter.op == null || filter.value> the method returns null
public static String <T> localize(Localizable fieldName, SimpleFilter<T> filter)
#localize(forI18nLabel("SALARY"),salaryFilter)
#salaryFilter = {op:"lt",value:10000}
#Salary is less than 10000 (en)
Now the problem is that the the upper bound U of my generics is Serializable and developer inadvertently invoked localizeEq, which accepts atomic values, with a parameter of type SimpleFilter<?> that extends Serializable. The method localizeEq builds a filter text "[field name] is equal to {op:null,value:null}".
The main issue is the null check. Methods that operate on atomic values (e.g. localizeEq, localizeNe) check if the parameter is null. Methods that operate on complex filters check that either the filter parameter is null or its value is null before going on.
That is the reason of the question. Obviously I can (will amend my code in order to) inspect the type of the value parameter when the method is invoked but has three drawbacks:
Developers find it only at runtime
Developers find the problem only when value is not null
Nobody in my company runs automated tests, so they will find out only when kickstarting the entire application and setting a non-null value to the filter. Once a manual test is done, it is never repeated
[Edit]
For my specific case there is another trick, but it involves creating more than a dozen overloaded deprecated methods:
#Deprecated
public static String localize[Eq|Ne...](Localizable fieldName, SimpleFilter<?> value){ throw new UnsupportedOperationException("Wrong method");}
[Edit 3]
The code is on Gist. Please note that in repository code we statically import SimpleFilter.filter or LocalDateRangeFilter.filter methods. In the question it is assumed that localize(Localizable,SimpleFilter) is part of the same class than other methods. And please note there are a few other *RangeFilter classes to support Joda Time, Java Util Date and NumericRange in our repository. They all suffer same issue.
I would like to focus anyway on the scope of the question: forbidding extension in generic, which seems not possible in the JLS.
I would like to ask if it is possible in Java 8+ to declare a generic
bound T so that it extends superclass/superinterface U (which could be
Object, or Serializable) but breaks compilation if T extends L (which
must extend U first).
The T in your pseudocode seems to be a type parameter, not a bound. Bounds are something different, and in fact, putting a bound on T seems to be what you are asking about. Indeed, without one -- in particular, without a lower bound -- your localizeEq() method is not gaining anything from being generic. As it stands, that method would be clearer if you just got rid of T altogether, and declared the second parameter to be of type Object (which would be equivalent to the current code) or Serializable or whatever.
I take it that the method was made generic in hopes of somehow using its type parameter to exclude arguments of certain subtypes, but that is not possible in Java, because
lower type bounds are inclusive, not exclusive
lower type bounds limit types meeting the bound to a single line of inheritance, which seems inconsistent with your intent
Now the problem is that the the upper bound U of my generics is
Serializable and developer inadvertently invoked localizeEq, which
accepts atomic values, with a parameter of type SimpleFilter<?> that
extends Serializable. The method localizeEq builds a filter text
"[field name] is equal to {op:null,value:null}".
If one is not supposed to pass a SimpleFilter to the localizedEq() method then I'd say that you have a design flaw here. You could catch violations at runtime, of course, but the type system does not provide a way to express the compile-time constraint you're looking for.
For my specific case there is another trick, but it involves creating more than a dozen overloaded deprecated methods:
Indeed, overloading is probably the best available solution, but I would suggest approaching it from the other direction. Instead of adding overloads for localizeEq, localizeNe, etc., deprecate the existing versions of those methods and instead overload localize with a version or versions that provide the wanted behavior for arguments that are not SimpleFilters.
I have the following class:
public abstract Foo {
Foo() {}
public abstract Foo doSomething();
public static Foo create() {
return new SomePrivateSubclassOfFoo();
}
}
I want to change it to the following definition:
public abstract Foo<T extends Foo<T>> {
Foo() {}
public abstract T doSomething();
public static Foo<?> create() {
return new SomePrivateSubclassOfFoo();
}
}
Is this change binary compatible?
I.e., will code that is compiled against the old version of the class work with the new version without reocmpilation?
I know that I need to change SomePrivateSubclassOfFoo, this is ok. I also know that this change will trigger warnings about raw types when old client code is compiled, this is also ok for me. I just want to make sure that old client code does not need to be recompiled.
From my understanding, this should be ok because the erasure of T is Foo, and thus the signature of doSomething in the byte code is the same as before. If I look at the internal type signatures printed by javap -s, I indeed see this confirmed (although the "non-internal" type signatures printed without -s do differ).
I also did test this, and it worked for me.
However, the Java API Compliance Checker tells me that the two versions are not binary compatible.
So what is correct? Does the JLS guarantee binary compatibility here, or was I just lucky in my tests? (Why could this happen?)
Well yes your code does not seem to break binary compatibility.
I found these after some crawling/reading http://docs.oracle.com/javase/specs/jls/se8/html/jls-13.html#jls-13.4.5
which says:-
Adding or removing a type parameter of a class does not, in itself, have any implications for binary compatibility.
...
Changing the first bound of a type parameter of a class may change the erasure (§4.6) of any member that uses that type parameter in its own type, and this may affect binary compatibility. The change of such a bound is analogous to the change of the first bound of a type parameter of a method or constructor (§13.4.13).
And this http://wiki.eclipse.org/Evolving_Java-based_APIs_2#Turning_non-generic_types_and_methods_into_generic_ones further clarifies:-
According to the special compatibility story, the Java compiler treats a raw type as a reference to the type's erasure. An existing type can be evolved into a generic type by adding type parameters to the type declaration and judiciously introducing uses of the type variables into the signatures of its existing methods and fields. As long as the erasure looks like the corresponding declaration prior to generification, the change is binary compatible with existing code.
So you have no problems as of now since it is the first time you are generifying that class.
But please keep in mind as the above doc also says :-
But, also bear in mind that there are severe constraints on how a type or method that already is generic can be compatibly evolved with respect to its type parameters (see the tables above). So if you plan to generify an API, remember that you only get one chance (release), to get it right. In particular, if you change a type in an API signature from the raw type "List" to "List<?>" or "List<Object>", you will be locked into that decision. The moral is that generifying an existing API is something that should be considered from the perspective of the API as a whole rather than piecemeal on a method-by-method or class-by-class basis.
So I think, its alright to make this change for the very first time but you have one chance only so make full use of it!
This program compiles and runs in C++ but doesn't in a number of different languages, like Java and C#.
#include <iostream>
using namespace std;
void foo2() {
cout << "foo 2.\n";
}
void foo() {
return foo2();
}
int main() {
foo();
return 0;
}
In Java this gives a compiler error like 'Void methods cannot return a value'. But since the method being called is a void itself, it doesn't return a value. I understand that a construct like this is probably prohibited for the sake of readability. Are there any other objections?
Edit: For future reference, I found some a similar question here return-void-type-in-c-and-c
In my humble opinion this question isn't answered yet.
The reply 'Because it says so in the specification, move on' doesn't cut it, since someone had to write the specification in the first place. Maybe I should have asked 'What are the pros and cons of allowing returning a void type like C++'?
It's because of the possibility of its usage in templates. C# and Java forbid void as a type argument, but C++ permits it to allow you to write template code like this:
template<typename T, typename TResult>
TResult foo(T x, T y)
{
return foo2(x, y);
}
If void methods weren't allowed to return a void expression, this template instantiation would be impossible if TResult was void. If that were the case, you would need a separate template definition if you ever wanted TResult to actually be void.
For example, remember how in C# there are two sets of generic general-purpose delegates, namely Func<> and Action<>? Well, Action<T> exists precisely because Func<T, void> is forbidden. The C++ designers didn't want to introduce situations like this wherever possible, so they decided to allow you to use void as a template argument -- and the case you found is a feature to facilitate exactly that.
(Allow me to write the rest in a pretend-Q&A format.)
But why do C# and Java not allow a similar construct?
First, realize how generic programming is made possible in those languages:
C# and Java generics work by parsing a generic type (or method) definition and making sure it is valid for the generic constraints/bounds you have provided.
C++ templates are a search-and-replace mechanism with a powerful metaprogramming language around them. They are not required to make sense in the absence of specific template arguments -- they go from the "template metalanguage" to the "C++ language" (so to speak) only when they get their hands on actual arguments.
Why pick one approach of implementing generic programming over the other?
The generics approach maintains the nominal typing of the rest of the language. This has the advantage of allowing the (AOT) compiler to do static analysis, type checking, error reporting, overload resolution and eventually code generation once.
The templates approach is essentially duck typing. Duck typing in a nominally typed language doesn't have the advantages described above, but it allows you more flexibility in the sense that it will permit potentially "invalid" things ("invalid" from the point of view of a nominal type system) as long as you don't actually mention those invalid possibilities anywhere in your program. In other words, templates allow you to express a larger set of cases uniformly.
Okay, so what would C# and Java need to do to support void as a valid generic argument?
I would have to speculate to answer this, but I'll try.
At the language level, they would have to waive the notion that return; is valid only in void methods and always invalid for non-void methods. Without this change, very few useful methods could be instantiated -- and they would all probably have to end with recursion or an unconditional throw (which satisfies both void and non-void methods without returning). So to make this useful, C# and Java would also have to introduce the C++ feature of allowing you to return void expressions.
Okay, let's assume you have that and now you can write code like this:
void Foo2() { }
void Foo()
{
return Foo2();
}
Again, the non-generic version is as useless in C# and Java as it is in C++. But let's move on and see its real usefulness, which is in generics.
You should now be able to write generic code like this -- and TResult could now be void (in addition to all the other types that were already permitted):
TResult Foo<T, TResult>(T a)
{
return Foo2(a);
}
But remember that in C# and Java, overload resolution happens "early", rather than "late". The same callee will be chosen by the overload resolution algorithm for every possible TResult. And the type checker will have to complain, because you're either returning a void expression from a possibly non-void method or you're returning a non-void expression from a possibly void method.
In other words, the outer method can't be generic, unless:
The callee is also generic and its return type is defined by a generic type parameter that matches that of the outer method.
Overload resolution in generic types and methods is postponed until actual type arguments are made available, so that we can pick a correct non-generic method at the call spot.
What if we went with the first option - make the callee's return type generic and move on?
We could do that, but it simply pushes our problem to the callee.
At some point, we would need some way to "instantiate" some kind of void instance and optionally be able to receive it somehow. So now we would need constructors for void (although every void method could count as a factory method, if you squint) and we would also need variables of type void, possible conversions from void to object, and so on.
Basically, void would have to become a regular type (e.g. a regular empty struct) for all intents and purposes. The implications of this aren't terrible, but I think you can see why C# and Java avoided it.
What about the second option - postpone overload resolution?
Also entirely possible, but note that it would effectively turn generics into weaker templates. ("Weaker" in the sense that C++ templates aren't restricted to typenames.)
Again, it wouldn't be the end of the world, but it would involve losing the advantages of generics that I described earlier. The designers of C# and Java clearly want to keep those advantages.
Sidenote:
In C#, there is one special case I know of, where binding happens after the validation of the generic type definition. If you have a new() constraint on a T and you attempt to instantiate a new T(), the compiler will generate code that checks whether T is a value type or not. Then:
For value types, new T() becomes default(T) -- remember that C# default struct constructors aren't really constructors in the CLR sense.
For reference types, Activator.CreateInstance is called, which is an indirect constructor invocation using reflection.
This particular case is very special because, even though it has completely postponed method binding to the runtime, the compiler can still perform static analysis, type checking and code generation once. After all, the type of the expression new T() is always T and a call to something that has an empty formal parameter list can be trivially resolved and verified.
According to the Java Language Specification §14.17:
A return statement with no Expression must be contained in one of the following, or a compile-time error occurs:
A method that is declared, using the keyword void, not to return a value (§8.4.5)
...
A return statement with an Expression must be contained in one of the following, or a compile-time error occurs:
A method that is declared to return a value
...
So, by declaring that a method is void, you are saying that it returns no value, so you are limited to using a return; statement with no expression.
So, I'm looking through a java library (JScience) after someone here thoughfully pointed me towards it for getting Vectors (mathematical ones, that is) in java.
Unfortunately, I've never seen anything in my life before like:
public static <F extends Field<F>> DenseVector<F> valueOf(F... elements)
as a method you can call in the DenseVector class. What...does that even mean. Is it returning a "<F extends Field<F>>" (and if so, why does Eclipse think it's an input?)
http://jscience.org/api/org/jscience/mathematics/vector/DenseVector.html#valueOf(F...)
It really confuses me. I can't make a new DenseVector() because only the super class has that, and it's protected, and trying to do DenseVector.valueOf() apparently only works if I give it...that...weird thing as an input.
I've seen people having to instantiate methods when trying to instantiate objects (or something like that)...is that like that (or IS it that?)) What is the API trying to get me to do?
I'm kind of confused that I've learned java in school (and used it a bit at work, though we use a lot of differnet stuff besides just java), and never came across anything like this. What's it for? What's it trying to get me to do? Is it new? Old? Obscure?
-Jenny
You should be able to invoke this method to create a vector, like this:
Real r1 = Real.ONE, r2 = Real.valueOf(2D), r3 = Real.ZERO;
DenseVector<Real> v = valueOf(r1, r2, r3);
In this example, the type argument F is Real. Real obeys the constraint "extends Field<F>" because it implements Field<Real>.
For different applications, different fields are likely to be used. For example, security applications might use the ModuloInteger field. It's a little confusing because this is a mathematical field, not a "vector field" like one talks about in physics.
By using type variables, this library helps to make sure you perform all operations within a given field. For example, given v declared as a DenseVector<Real> like above, the compiler will complain if you try to multiply it by a Complex number.
It's a generic return type. See here for a tutorial on Java Generics.
These are called Generic types. They've been added in Java 5 and are similar to C++ templates.
The idea is that you define a collection of items of a particular type rather than something general.
This helps you avoid frequent downcasting. In older Java code, suppose that you knew your vector would contain only X's. Once you retrieved items out of that collection, you would just get Object, and you had to explicitly downcast it.
It is also safer because you can't put Ys into a vector of Xs, and clearer to read for the same reasons.
The story behinds the "extends" in these brackets is that you can define collections of "Xs and all their subtypes" that would still accept subtypes of X but reject Y.
public static <F extends Field<F>> DenseVector<F> valueOf(F... elements)
Lets break this down:
public static
Its a public static method.
<F extends Field<F>>
Its a generic method for any class F where F is an extention of Field
DenseVector<F>
It returns a (generic) DenseVector for F
valueOf(F... elements)
A method named valueOf where parameters are zero or more Fs.