Concept of varargs and ambiguity? - java

Here's an example:
package com.demo;
public class PassArray {
static void vaTest(int... v){
System.out.println("no of args : "+v.length+"contents: ");
for (int x:v){
System.out.println(x+" ");
}
}
static void vaTest(boolean... v){
System.out.println("no of args : "+v.length+"contents: ");
for (boolean x:v){
System.out.println(x+" ");
}
}
public static void main(String args[]){
vaTest(1,2,3);
vaTest(true,false,true);
vaTest();//Error:Ambiguous!
}
}
Can anyone tell me :
I have some Question
1.Why ambiguous error occure ?
2.i have one Varargs parameter just like
int doIt(int a,int b,int c,int... vals)
Why varargs must be declared last ?
What is varargs and ambiguity ?

Since there are two legal method invocations to the call vaTest();, the compiler can't figure out which one to use.
To help it out, you can provide an empty array of the chosen type:
vaTest(new int[] {});
More info is available in the JLS 15.12.2.5. Choosing the Most Specific Method.

Why ambiguous error occure ?
Because you haven't passed any arguments, and both the methods are valid candidate for invocation, as both can be invoked without any argument. The compiler cannot decide onto which method to bind the method call, as there is no parameter type to distinguish between the methods.
Why varargs must be declared last ?
Well, because that's how people who created Java wanted it to be declared. May be they wanted the task for the compiler easy. If the varargs are declared as last parameter, the compiler can just go on to bind all the arguments after the last non-vararg parameter to the vararg parameter. Of course, it would have been possible even if the vararg was allowed somewhere in the middle, but that would require compiler to bind the parameters towards the ends first, or at least some kind of algorithm to find out that there are enough arguments left to bind to the further non-vararg parameters. That would have made the parsing complex, as the compiler binds method argument left-to-right (that would have required some changes). May be language creator thought, adding this feature will not weigh much to justify the changes in how compiler binds the arguments. So, this restriction.

1.Why ambiguous error occure ?
This part has been already answer by other user, nicely.
Why varargs must be declared last ?
Well this is how JAVA is written. The reasonable explanation i can think of is keeping the usual read direction of the parenthesis () which has Associativity: left-to-right, If we are to declare a function like:
public void aFunc(String... args, String x, String y, String z)
If we invoke this function with exactly three arguments:aFunc("arg1", "arg2", "arg3"): Then we have a decision problem: which variable should belong to variable arity parameter args? To know the answer we will have to go from right-to-left, just reverse of the usual order of the parenthesis () associativity.

Related

Cast to instance's type automatically

I have a function that should take an instance of anything extending Object, and just pass the casted instance to a function. I don't want to use a switch, as the function can accept a huge number of object types, so it would become a very big method.
public void attachBufferData(ContextConstant bufferType, Object<T> data, ContextConstant usage) {
glBufferData(bufferType.getGLType(), (T) data, usage.getGLType());
}
The code above doesn't work (as Object isn't a generic type), but it should get across what I'm trying to do.
----- EDIT -----
Ok, I tried this:
public void attachBufferData(ContextConstant bufferType, Object data, Class<?> dataType, ContextConstant usage) {
glBufferData(bufferType.getGLType(), dataType.cast(data), usage.getGLType());
}
But I get a compile error glBufferData(int, long, int) is not applicable for arguments (int, capture#1-of ?, int). I guess it's a massive switch statement then :(
You can't do it like this, I'm afraid. There are three things to consider. I think (2) is the one you really want, but I'm not absolutely certain, so I've left all three issues in there for you to think about.
What signature does glBufferData() have (if it's not overloaded)? If its second parameter is of type Object, then whatever you pass will end up being viewed as an Object there, even if it's a subclass, so you wouldn't achieve anything by having it cast. You might as well just have the type of data as the same type as the second parameter to glBufferData().
If glBufferData() is an overloaded method, and you want to be calling the right one, then you can't do it dynamically: you need some code to test the real type of the class at runtime, and then you choose the right version to call. Choice of overloaded method gets resolved at compile time, not runtime, so you can't just pass it a specific instance you don't know about at compile time and then have it select the right version.
If glBufferData() is a non-overloaded method you've written, contained within your class, then you do have another and better option, which is to make your class generic. If your class takes a type parameter of T, then you can have T data as the second parameter of attachBufferData(), and you can have T data as the second parameter of glBufferData(), so that the types match up.
The point about method overloading is that it's not nearly as clever as it looks. As far as the compiler is concerned, there's really no difference between these two cases.
Case 1:
public void f(int x);
public void f(String s);
Case 2:
public void f(int x);
public void g(String s);
Although we think of case 1 as having just one overloaded method, and case 2 as having two separate methods, as far as the compiler's concerned, in each case there are two distinct methods, and they're distinct because they have distinct signatures (ignoring return type). In both cases, the compiler can choose the right method to call based on the code you write, because it can look at the type of the arguments and the name of the method you've asked for, and find one that matches. The fact that two have the same name is of no more significance than having two methods with different names but the same parameter types.
There's no mechanism for choosing which method to call at runtime in case 1, any more than there is in case 2.
You can declare the type at class level and reuse it wherever required, below is an example.
public class ExceptionHolder<T>
{
private List<T> errors = new ArrayList<T>();
public void addError( T t )
{
errors.add( t );
}
public void addError( List<T> t )
{
errors.addAll( t );
}
}
In the calling code
ExceptionHolder<String> exHolder = new ExceptionHolder<String>();
String can be substitued for any object as needed.

variable argument in java

public class Demo {
public static String doit(int x,int y)
{
return"a";
}
public static String doit(int ...val)
{
return "b";
}
public static void main(String args[])
{
System.out.println(doit(4,5));
}
}
I have a doubt that why compilier is not showing any error since doit(4,5) is causing ambiguity
When I ru the code ,I get output as a ad not b why?
The Java Language Specification defines that first method ("a") should be called (rather than "b").
See http://docs.oracle.com/javase/specs/jls/se5.0/html/expressions.html#15.12.2
In order to maintain backwards compatibility with previous Java versions (before varargs was introduced), the compiler will always pick a method with the exact number of arguments, even if a varargs method also exists.
As to whether you get a warning or not, compilers are free to add additional warnings, and there may be some that do warn about this situation, I guess yours doesn't (at least not with the settings you have)
The JLS specifies the rules that are used to resolve ambiguity. The simplified version is that the compiler first attempts to match the call against the available overloads treating the varadic argument as a simple array. If that succeeds, that is it. If it fails, it tries again treating the last argument as varadic.
In this case, the first round of matching gives a definite match.
If you are interested, the JLS rules for determining what method should be used are given in Section 15.12.2. (Warning: actual JLS rules are significantly more involved than the simplified version above, and the language / notation used is very technical.)
public static String doit(int ...val)
{
return "b";
}
will be treated by compiler as
public static String doit(int[] val)
{
return "b";
}
when passing doit(2,2), 1st method will be called, as the arguments are not an array.
When passing doit(2,2,2), the arguments will converted to array and passed to 2nd method.
change the 1st method to
public static String doit(int x,int ...y)
{
return"a";
}
call doid(2,2), it will say error
doit(int, int[]) is ambigious.
Compiler always attempts to resolve the call to the most specific function call it can find which in this case is method A. This is not really a bug but if you consider it as such it's not a compiler bug, it's in the specs. You should see the crazy stuff you could get out of this once autoboxing comes into play.
The compiler tries to match the most specific alternative. It can however be argued that it should cause an ambiguity error.
From the Java Language Specification
15.12.2.5
If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.
This is a compromise they made when doing the varargs spec (it's hard to know which gets called). It is recommended not to overload varargs method for this reason. Quote from their site:
Generally speaking, you should not overload a varargs method, or it will be difficult for programmers to figure out which overloading gets called.

Understanding which constructor is chosen and why

Why following program every time prints I'm string and not I'm object. or I'm int.?
public class Demo {
public Demo(String s){
System.out.println("I'm string");
}
public Demo(int i){
System.out.println("I'm int.");
}
public Demo(Object o){
System.out.println("I'm object.");
}
public static void main(String[] args) {
new Demo(null);
}
}
Also if I replace int with Integer. It gives error as The constructor Demo(String) is ambiguous. Why?
null can be converted to Object or String, but not int. Therefore the second constructor is out.
Between the conversion to Object or the conversion to String, the conversion to String is more specific, so that's what's picked.
The JLS section 15.12.2 describes method overload resolution, and I believe the same approach is used for constructor resolution. Section 15.12.2.5 describes choosing the most specific method (constructor in this case):
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.
This about the constructor invocation with Object or String arguments - any invocation handled by new Demo(String) could also be passed on to new Demo(Object) without a compile-time type error, but the reverse is not true, therefore the new Demo(String) one is more specific... and thus chosen by the overload resolution rules.
To answer your second question (since Jon Skeet has already covered the first), when you have both a String constructor and an Integer constructor the compiler doesn't know what you mean by null in new Demo(null): it could be either a String or an Integer.
Because String can't be cast to Integer (and vice versa) the compiler gives up and reports the ambiguous error. This is in contrast to the String vs Object choice when you don't have the Integer constructor.
When you have constructors or methods like the above, the compiler generally tries to find the closest match possible and uses that.
The way to think of null in these circumstances is it acts as a subtype of all types (yes, it's not strictly speaking true but it provides a good platform for thinking about what happens). So using this rule it fits string more closely than object, hence this is the constructor that is executed.
The fact the String constructor is mentioned in by the compiler in your second error:
The constructor Demo(String) is ambiguous.
is not significant. This is because the Constructor which takes a String is the first declared constructor, so the compiler uses it in its error message. Change to have the Object constructor first and you get:
The constructor Demo(Object) is ambiguous.
What it's trying to say is there's ambiguity between the constructor which takes the Integer and the Object, so you have to be more specific, as null can be applied to each. Integer IS-NOT-A String, so the two types are not compatible. You need to be more specific so the compiler can bind the constructor call.
See #Jon Skeet answer for why the compiler raises an error in some instances and not in others.

What does "..." mean in java? [duplicate]

I have been writing java for a while, and today I encountered the following declaration:
public static void main(String... args) {
}
Note the "dot dot dot" in the array declaration, rather than the usual bracket []. Clearly it works. In fact I wrote a small test and verified it works. So, I pulled the java grammar to see where this syntax of argument declaration is, but did not find anything.
So to the experts out there, how does this work? Is it part of the grammar? Also, while I can declare function like this, I can't declare an array within a function's body like this.
Anyway, do you know of any place that has this documented. It is curiosity, and perhaps not worth of any time invested in it, but I was stumped.
I believe this was implemented in Java 1.5. The syntax allows you to call a method with a comma separated list of arguments instead of an array.
public static void main(String... args);
main("this", "is", "multiple", "strings");
is the same as:
public static void main(String[] args);
main(new String[] {"this", "is", "multiple", "strings"});
http://today.java.net/article/2004/04/13/java-tech-using-variable-arguments
http://download.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
Check out the Java Language Specification, Third Edition, Chapter 8 (Classes). Buried in there is this nugget:
If the last formal parameter is a variable arity parameter of type T, it is considered to define a formal parameter of type T[]. The method is then a variable arity method. Otherwise, it is a fixed arity method. Invocations of a variable arity method may contain more actual argument expressions than formal parameters. All the actual argument expressions that do not correspond to the formal parameters preceding the variable arity parameter will be evaluated and the results stored into an array that will be passed to the method invocation (§15.12.4.2).
Basically, the last parameter of any method call can have T.... If it has that, it is converted to T[].
So basically, what you have is a fancy way of reproducing the more traditional
String[] args
It is varargs
In simple term its an Array of Member like
public setMembers(Member[] members);
When to use:
Generally while designing API it is good to use when number of argument is not fixed.
Example from standard API of this is String.format(String format,Object... args)
Also See
var-arg-of-object-arrays-vs-object-array-trying-to-understand-a-scjp-self-test
This is called variadic arguments, check here:
http://en.wikipedia.org/wiki/Variadic_function#Variadic_functions_in_C.23.2C_C.2B.2B.2FCLI.2C_VB.net.2C_and_Java
The official documentation (Java 1.5) is here:
http://download.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
It's the so-called varargs syntax. In the method body, you can read the members parameter as it were an array - actually, it /is/ 'just' an array.
However, the magic bit is in calling the method. Before the varargs syntax was introduced, you'd call the method a bit like so:
setMembers(new Members[] {member1, member2, member3});
With the new varargs syntax however, you don't need to explicitly create the array anymore, and you can pass:
setMembers(member1, member2, member3);
This does mean however that a varargs argument has to be the last argument in a method. Something like this is therefore not permitted:
void setMembers(Member ... members, String memberType);
Summarized: It's a bit of syntactic sugar, really. I'm no expert on the inner workings of the Java compiler, but I'm pretty sure that methods calling a method that accept a varargs parameter are rebuilt into methods that build an array of the given type.
You might want to read up on Using Variable Arguments (or varargs) in Java.
It's called varadic argument: A function that takes as many (including zero) arguments as you want.
For example, main("string1", "string2", "string3") is same as main({"string1", "string2", "string3"}) if main is declared as void main(String...args).
See http://www.java-tips.org/blog/java-se/varargs-%E2%80%93-java-50-addition.html
It means you can pass zero or more Member objects to the setMembers() method. In the setMembers method, members will have array semantics.
Variable arguments. Can have 0 or more String arguments.
The function can access the parameters as an array of Strings.
It means that the method accepts a variable number of String arguments. The arguments are treated as an array and so are accessed by subscript, in the order they are passed in.

What does "..." mean in Java? [duplicate]

I have been writing java for a while, and today I encountered the following declaration:
public static void main(String... args) {
}
Note the "dot dot dot" in the array declaration, rather than the usual bracket []. Clearly it works. In fact I wrote a small test and verified it works. So, I pulled the java grammar to see where this syntax of argument declaration is, but did not find anything.
So to the experts out there, how does this work? Is it part of the grammar? Also, while I can declare function like this, I can't declare an array within a function's body like this.
Anyway, do you know of any place that has this documented. It is curiosity, and perhaps not worth of any time invested in it, but I was stumped.
I believe this was implemented in Java 1.5. The syntax allows you to call a method with a comma separated list of arguments instead of an array.
public static void main(String... args);
main("this", "is", "multiple", "strings");
is the same as:
public static void main(String[] args);
main(new String[] {"this", "is", "multiple", "strings"});
http://today.java.net/article/2004/04/13/java-tech-using-variable-arguments
http://download.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
Check out the Java Language Specification, Third Edition, Chapter 8 (Classes). Buried in there is this nugget:
If the last formal parameter is a variable arity parameter of type T, it is considered to define a formal parameter of type T[]. The method is then a variable arity method. Otherwise, it is a fixed arity method. Invocations of a variable arity method may contain more actual argument expressions than formal parameters. All the actual argument expressions that do not correspond to the formal parameters preceding the variable arity parameter will be evaluated and the results stored into an array that will be passed to the method invocation (§15.12.4.2).
Basically, the last parameter of any method call can have T.... If it has that, it is converted to T[].
So basically, what you have is a fancy way of reproducing the more traditional
String[] args
It is varargs
In simple term its an Array of Member like
public setMembers(Member[] members);
When to use:
Generally while designing API it is good to use when number of argument is not fixed.
Example from standard API of this is String.format(String format,Object... args)
Also See
var-arg-of-object-arrays-vs-object-array-trying-to-understand-a-scjp-self-test
This is called variadic arguments, check here:
http://en.wikipedia.org/wiki/Variadic_function#Variadic_functions_in_C.23.2C_C.2B.2B.2FCLI.2C_VB.net.2C_and_Java
The official documentation (Java 1.5) is here:
http://download.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
It's the so-called varargs syntax. In the method body, you can read the members parameter as it were an array - actually, it /is/ 'just' an array.
However, the magic bit is in calling the method. Before the varargs syntax was introduced, you'd call the method a bit like so:
setMembers(new Members[] {member1, member2, member3});
With the new varargs syntax however, you don't need to explicitly create the array anymore, and you can pass:
setMembers(member1, member2, member3);
This does mean however that a varargs argument has to be the last argument in a method. Something like this is therefore not permitted:
void setMembers(Member ... members, String memberType);
Summarized: It's a bit of syntactic sugar, really. I'm no expert on the inner workings of the Java compiler, but I'm pretty sure that methods calling a method that accept a varargs parameter are rebuilt into methods that build an array of the given type.
You might want to read up on Using Variable Arguments (or varargs) in Java.
It's called varadic argument: A function that takes as many (including zero) arguments as you want.
For example, main("string1", "string2", "string3") is same as main({"string1", "string2", "string3"}) if main is declared as void main(String...args).
See http://www.java-tips.org/blog/java-se/varargs-%E2%80%93-java-50-addition.html
It means you can pass zero or more Member objects to the setMembers() method. In the setMembers method, members will have array semantics.
Variable arguments. Can have 0 or more String arguments.
The function can access the parameters as an array of Strings.
It means that the method accepts a variable number of String arguments. The arguments are treated as an array and so are accessed by subscript, in the order they are passed in.

Categories

Resources