top | item 4365967

Named Parameters in Java

17 points| javinpaul | 13 years ago |java.dzone.com | reply

60 comments

order
[+] jasonkolb|13 years ago|reply
Wow this would make for some crazy code to try to read thru. I would be über-pissed to trace thru code like this only to find all of these wrapper classes. This is what Javadocs are for, it's much easier and cleaner just to document your code as you write it.
[+] tsewlliw|13 years ago|reply
This. I'd do my best to make sure the authors contributions stopped. Type safety obviously doesn't protect you the worst possibilities in software.
[+] flatline3|13 years ago|reply
> I would be über-pissed to trace thru code like this only to find all of these wrapper classes.

Why? I think this code is better; to demonstrate why, I'll deconstruct the first example -- names.

Names aren't strings. Names are multi-component entities comprised of strings with rather complex internationalization rules regarding composition.

To properly represent a name, you need the set of fields that compose the name, along with a 'full name' (historically in x.500 and LDAP this is called the 'commonName') that is pre-composed according to the users preference.

Some of the individual components you'll need if you wish to compose names:

- Surname [may be more than one]

- Middle name [may be more than one]

- Given name [may be more than one]

- Prefix (title, etc) [may be more than one]

- Suffix (IIrd, etc) [may be more than one]

- Nick name

The rules for composition can be complicated, so you'll want to centralize them somewhere. Also, you may not want to build a super-complex name class now, but later you might need to start sending out e-mails with "Mr. Psuedonym" at the top.

So how do you handle this?

CREATE A CLASS.

Names aren't strings. Most things aren't strings, though they may be represented as strings. Create a class now and make it easy to extend types later.

Treating everything as strings and ints throws away more than just the type system -- it throws away much of the code maintenance value of OO!

That's just names. His example also uses file paths, and file paths are actually quite similar to names; they're composed of multiple components, they have very specific rules regarding composition and normalization, and unlike names, you can easily introduce security issues by incorrectly handling file paths (eg, failure to correctly normalize a path before applying security checks).

This is why we create File classes that handle normalization/composition/decomposition of path names. As a side effect, it also helps constrain the types of your method calls.

Personally, I'm "über-pissed" when I trace through code that uses raw "string & int programming" and does not properly leverage types. It makes for messy code that does not properly take advantage of OO encapsulation and is difficult to read, difficult to type-check, is difficult to maintain, and even more difficult to build on.

[+] cpt1138|13 years ago|reply
Wouldn't the Builder pattern address this issue? So you can do:

object.setName("Alfred E. Neumann") .setLink("http://blog.schauderhaft.de) .setUltimateAnswer(42) .setTempFile("c:\\temp\\x.txt") .setZip(23);

[+] Aykroyd|13 years ago|reply
That would definitely be a nicer way to do it. Although, using the builder pattern to create parameters for every single method in your API would be a gigantic pain.

Javascript APIs hack this in by taking Objects as params so that you can do {name='Alfred E. Neuman'...}. Unfortunately, Java's syntax isn't nice for creating Maps either, but maybe you could do something with that.

In the end, this seems like a problem with the language syntax and any fix other than one at the language level is going to be a hack.

[+] devgutt|13 years ago|reply
I think this way is better:

  o.doSomething({
    name : "Alfred E. Neumann",
    link : "http://blog.schauderhaft.de,
    ultimateAnswer: 42,
    tempFile: "c:\\temp\\x.txt",
    zip : 23});
[+] moondowner|13 years ago|reply
or ObjectName.getBuilder("Alfred E. Neumann", "http://blog.schauderhaft.de, 42, "c:\\temp\\x.txt", 23).build(); maybe?

It's not addressing named parameters issue, but I find it better like this.

[+] dhimes|13 years ago|reply
Whoever wrote the original code is missing a major point in OOP: you should (almost) never be passing in simple types. Create an object that holds the data (class IDObject, for instance), and pass an instance of this class in for the parameter. Then, the parameters are de facto named in the data object.

This importance of this method is that it allows the you to update the information passed in via the data object (when ID needs change, and they will over the course of a project) without breaking the interface. And that's the point of it all.

[+] nessus42|13 years ago|reply
On the other hand, the Law of Demeter says that you should almost always be passing in and fetching primitive types. At least in an API. Does it not?

Though I'm guessing that "primitive types" would include algebraic data types, which serve the same purpose here as little objects like IDObject. And since Java doesn't have algebraic data types.... All the more reason to switch to Scala.

Edit: I should have written "built-in types" above, rather than "primitive types".

[+] TazeTSchnitzel|13 years ago|reply
Never passing in simple types?

I don't know about you, but one of the reasons I like languages such as Python and JavaScript is I don't have to create a wrapper object for every type I'm using. The fact I had to, for instance, create URL and IP Address and such objects in C# drove me crazy.

[+] Roboprog|13 years ago|reply
OTOH, I kind of like languages that support map literals and/or tuples, rather than making me define a new class for use in a single place as a parameter object or return value.

On the gripping hand: click on the method name (in an IDE), and let the IDE tell you what the params are to the method. Why bother with static typing if you aren't going to use the information?

[+] sixbrx|13 years ago|reply
I think types are orthogonal to why named parameters are helpful, because parameters don't just indicate a type but a particular usage of a type.

So for example, in a bank transfer method the named parameter would help distinguish the from-account from the to-account. The accounts are already not simple types, but their usages (roles in the sentence underlying the semantics of the method) are different.

You could create a "transfer" class of course for the pair of accounts, but are we going to do this for each combination of usages of our types. Hopefully not - we'd basically be encoding each combination of parameters that our methods accept into an object - not practical or productive in my opinion.

[+] columbo|13 years ago|reply
Interesting. But it looks like it is solving a problem with another problem. The receiving class would then look like this:

    public void doSomething(Name name, Link link, UltimateAnswer ultimateAnswer, TempFile tempFile, Zip zip) {
        String name = name.name;
        String link = link.link;
        int ultimateAnswer = ultimateAnswer.ultimateAnswer;
        String tempFile = tempFile.tempFile;
        int zip = zip.zip;
    }
If the problem is "I don't like these SAME values being used all over the place" then use DEFAULTS.

    o.doSomething1(); //defaults to "Alfred","c:\\temp",42,"shadurhaft.de",23
That or pass in an object. o.doSomething1(mySomethingObject);

If the values are genuinely different then the only way to solve this problem is to validate the options (paths should be a valid file location and not a website, websites should be a valid website etc) and then (possibly) pass in an object instead of primitives.

I don't see encapsulation doing anything really, aside from increasing the number of "junk" classed by about a hundred fold.

Why throw standard convention out the window?

[+] peeters|13 years ago|reply
I'm not sure I see the "another problem" you're referring to. Can you describe the problem with the new implementation of doSomething()?

Also, I don't think the original problem was the same values being used all over the place. The problem is how to be clear about which parameters you're providing, and accepting static types and giving the type a simple way of constructing it solves that.

[+] bchen|13 years ago|reply
Since long parameter list is considered a code smell, people should be discouraged from writing this kind of code anyways. Namely, this example from the article is in fact a bad practice:

> o.doSomething1("Alfred E. Neumann", "http://blog.schauderhaft.de, 42, "c:\\temp\\x.txt", 23);

As other commenters have pointed out, I think the builder pattern is one of the two solutions I would use. The other solution is to simply create an object that represents the values to be passed in to the method. Consider:

  User user = new User("Alfred E. Neumann");
  user.setLink("http://blog.schauderhaft.de);
  user.setUltimateAnswer(42);
  user.setTempFile("c:\\temp\\x.txt");
  user.setZip(23);
  o.doSomething(user);
Even with named parameters, I would say the latter approach is still superior than having a long parameter list.
[+] yarrel|13 years ago|reply
Named parameters would result in more readable, compact, and efficient code compared to the latter approach.

But yes, long parameter lists (whether represented as argument structs or not) generally indicate a problem.

[+] hnriot|13 years ago|reply
This, like many of the proposed solutions here exposes the issue that putting the (not particularly) long list of parameters into the ctor, that of not every being able to call doSomething without all the required values. What is the caller of your builder doesn't remember to set the zip and the doSomething method then uses it? You've only really added syntactic sugar and sacrificed functionality.
[+] pathdependent|13 years ago|reply
Although the solution produces too many problems, I agree that named parameters are highly desirable for readability and the prevention of bugs. Have there been any proposals for Java 8 to included named parameters?

Edit:

* http://openjdk.java.net/jeps/118 proposes run-time storing of parameter names -- not what is desired, but in the same ballpark.

* http://web.archiveorange.com/archive/v/bobySzLnuDWgr47zqwU9 proposes named arguments for making clean code.

[+] bad_user|13 years ago|reply
The problem with named parameters is that suddenly method parameters become part of your exposed API.

The other problem is that the compiler currently discards the parameter names, so older binaries are not going to be compatible.

[+] PaulHoule|13 years ago|reply
It might be crazy but I like this kind of DSLization of Java a lot
[+] peeters|13 years ago|reply
I've seen a pretty big move in popular libraries to fluent interfaces. It does a pretty good job of getting over the verbosity in Java (at least where the verbosity hurts readability).

Examples like Guava:

   Cache<String, User> userCache = CacheBuilder.newBuilder()
      .initialCapacity(7)
      .expireAfterWrite(20, TimeUnit.MINUTES)
      .build();
Or Hamcrest:

   assertThat(result, containsString("OK"));
Or Rest-Assured:

   expect().statusCode(200).when().get("/user/1");
[+] bartonfink|13 years ago|reply
I think it would really shine with IDE support. It probably wouldn't even be that hard to do (famous last words). I think I'll take a stab at it.

I like it as well, and have done similar things by creating input/output classes to use as "structs" when the list of parameters gets unweildy or when I want multiple returns.

[+] kd0amg|13 years ago|reply
It doesn't seem all that crazy to me. I wouldn't be surprised to see an ML programmer write something like

  datatype name = Name of string
and this is just the way to express that in Java.
[+] jebblue|13 years ago|reply
I would not use a separate class per parameter though that is a clever solution. It might hurt performance and it just feels a bit heavy.

For performance, clarity and reusability I would simply create a class that holds the values needed. Add an @Entity tag and now it can be used as a Hibernate persistence class too.

[+] josemando|13 years ago|reply
Coming back to Java after learning Objective-C made realize how named parameters are awesome
[+] SeanLuke|13 years ago|reply
Objective-C doesn't have named parameters (that is, Lisp-like "keyword" parameters). It has a hack which allows a method to be so named that it has to be used in a named way. Named parameters can be in any order and may or may not exist in the function call. Obj-C can't do this because its "names" are actually just part of the method signature. It's fake.
[+] erode|13 years ago|reply
I use named parameters in csharp, and they are nice, but they're not worth all that extra effort. The code is now much more confusing.
[+] x3eme|13 years ago|reply
or you know, use an IDE!
[+] jebblue|13 years ago|reply
This is a good observation, people who seem to like named parameters strike me as people who might code in plain text editors a lot. Nothing wrong with that but an IDE makes things so much easier and faster.