Skip to main content

Varargh!

Varargs, a feature of the C language since roughly the late Victorian era, was introduced into the Java language in JDK1.5.


I love varargs. They allow me to declare a function flexibly with the ability to take zero, one, or several parameters. This ability is useful when the user may have an unpredictable number of things to add to some data structure, eliminating the need for them to create some collection to pass the parameters into your function. It makes for a nice API. And I'm all about nice API. (And donuts).


But sometimes varargs don’t work so well. I suppose it’s because I expect too much of them. Like when you meet someone that you really like, so you call them every few minutes or so, then hang around outside their apartment and workplace and friends' houses until they get a restraining order on you. It’s not that they weren’t really cool and worth getting to know, but that your needs weren't necessarily compatible.


I was working recently on some API improvements for a library I'm writing. I had some constructors that users would call with exactly two values of different types, like this:



public MyObject(int value1, int value2) {}

public MyObject(float value1, float value2) {}


This worked well, vectoring the code path off in different directions depending on the types of the values that the user passed in.


But sometimes, the users might have just one value to pass in. Or three. Or nineteen. Rather than having variations for all of these situations, multiplied by the number of types that I wanted to support, I wanted something simpler that took variable numbers of parameters.


So I rewrote my API with varargs. It looked something like this:



public MyObject(int... values) {}

public MyObject(float... values) {}


This new version was awesome. Now the user could call my functions with the appropriate values and it would do the right thing, no matter what the types were or how many values they passed in. I compiled the code for the library, wrote my test code:



MyObject obj1 = new MyObject(1f);
MyObject obj2 = new MyObject(1);


and


FAIL

I got a compiler error. Specifically, Eclipse gave me the following completely unhelpful message for the test code: “The constructor MyObject(float[]) is ambiguous” for the second line of that test code (MyObject obj2 = new MyObject(1)).


Never mind the fact that the error was telling me that the constructor takes an array instead of varargs; I know that varargs is syntactic sugar for a construct that gets turned into an array. The real problem was that my code wouldn’t compile.


Apparently, varargs cannot handle the method overloading situation and make the correct type inference and just fails to compile. Although the compiler can make a good decision about the correctness of a constructor with float vs. int, it can’t make that decision for float[] vs int[]. So
it bails.


Meanwhile, I discovered another nuance of using varags; you can’t pass them around between constructors willy-nilly. One of the things I wanted to do in my rewrite was to record the type that the user wanted to use and send it to a private constructor like this:



private MyObject(Class valueType, Object... values) {}


Meanwhile, I wrote a single type-specific constructor (to avoid the previous compiler error for now) that called this more generic constructor:



public MyObject(float... values) {
this(float.class, values);
}


Again, my code compiled fine. And when I eliminated one of the float/int varargs combinations, I was able to write a test that successfully called my varargs constructor:



MyObject blah = new MyObject(1f, 2f, 3f);


This code called the private Object-based constructor above. But then I encountered bugs at runtime where the number of values was not what I was expected. In particular, the number of values being stored by the private constructor was 1, not 3.


But, but, but, ...


It turns out that the call to the private constructor turned a perfectly fine threesome of parameters of type float into a single parameter of type float[]. That is, my varargs had just turned into the array that it was pretending it wasn't when I first wrote the code.


At this point in an article, the climax as it were, I would typically say, “And here’s how you work around these issues.” I would love to do that, because I like neat tricks and workarounds. And I’d love to actually have that workaround in my code.


Unfortunately, I have no such workaround. I frankly don’t know how to make this work in any reasonable way. You can be more clear with the compiler, by telling it things like new MyObject(new float[](1f, 2f, 3f}) to get around the compiler error. And maybe you even like the way that that looks for an API. If you are sadistic. Or hallucinating. You could also find a different way to store the individual parameters in the varargs rather than having the VM think that it’s just a single array item. But at this point, my original attempt at a more attractive API and flexible implementation was looking like a bad prototype or an industrial accident.


So I did the only thing that any responsible captain would do after his vessel had hit an iceberg and was going down with all hands: abandon ship on the first lifeboat.


For my situation, I could limit the flexibility to just one or two parameters for the main case, and then have a completely different constructor with a custom data structure for the more
flexible, and less common, case of having several parameters. So I walked away from varargs
completely for my code with nary a look back. The second problem of calling the private constructor with varags then magically disappeared because I no longer had to pass the varargs around.


For other situations that may benefit from varags, but may run afoul of method overloading, I can only recommend that you know and understand the limitations of the nifty varargs feature. I searched around on the web for answers to my compiler problem and didn’t find anything immediately, so I thought it might be worth noting for posterity. Or at least for the pleasure of venting.


Varargs: great when they work. But when then don’t? Nobody knows. Maybe that's why the syntax uses ellipses. It's like a little language joke that says, "Sure, use varargs, Let's see what happens..."

Comments

Popular posts from this blog

Benefits Of Healthy eating Turmeric every day for the body

One teaspoon of turmeric a day to prevent inflammation, accumulation of toxins, pain, and the outbreak of cancer.  Yes, turmeric has been known since 2.5 centuries ago in India, as a plant anti-inflammatory / inflammatory, anti-bacterial, and also have a good detox properties, now proven to prevent Alzheimer's disease and cancer. Turmeric prevents inflammation:  For people who

Women and children overboard

It's the  Catch-22  of clinical trials: to protect pregnant women and children from the risks of untested drugs....we don't test drugs adequately for them. In the last few decades , we've been more concerned about the harms of research than of inadequately tested treatments for everyone, in fact. But for "vulnerable populations,"  like pregnant women and children, the default was to exclude them. And just in case any women might be, or might become, pregnant, it was often easier just to exclude us all from trials. It got so bad, that by the late 1990s, the FDA realized regulations and more for pregnant women - and women generally - had to change. The NIH (National Institutes of Health) took action too. And so few drugs had enough safety and efficacy information for children that, even in official circles, children were being called "therapeutic orphans."  Action began on that, too. There is still a long way to go. But this month there was a sign that

Not a word was spoken (but many were learned)

Video is often used in the EFL classroom for listening comprehension activities, facilitating discussions and, of course, language work. But how can you exploit silent films without any language in them? Since developing learners' linguistic resources should be our primary goal (well, at least the blogger behind the blog thinks so), here are four suggestions on how language (grammar and vocabulary) can be generated from silent clips. Split-viewing Split-viewing is an information gap activity where the class is split into groups with one group facing the screen and the other with their back to the screen. The ones facing the screen than report on what they have seen - this can be done WHILE as well as AFTER they watch. Alternatively, students who are not watching (the ones sitting with their backs to the screen) can be send out of the classroom and come up with a list of the questions to ask the 'watching group'. This works particularly well with action or crime scenes with