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.
> 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.
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.
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.
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".
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.
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?
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.
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.
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.
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:
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.
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.
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.
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).
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.
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.
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.
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.
[+] [-] jasonkolb|13 years ago|reply
[+] [-] tsewlliw|13 years ago|reply
[+] [-] flatline3|13 years ago|reply
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
object.setName("Alfred E. Neumann") .setLink("http://blog.schauderhaft.de) .setUltimateAnswer(42) .setTempFile("c:\\temp\\x.txt") .setZip(23);
[+] [-] Aykroyd|13 years ago|reply
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
[+] [-] moondowner|13 years ago|reply
It's not addressing named parameters issue, but I find it better like this.
[+] [-] dhimes|13 years ago|reply
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
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
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
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
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.
[+] [-] arethuza|13 years ago|reply
That sounds awfull like YAGNI would apply:
http://en.wikipedia.org/wiki/You_ain%27t_gonna_need_it
[+] [-] columbo|13 years ago|reply
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
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
> 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:
Even with named parameters, I would say the latter approach is still superior than having a long parameter list.[+] [-] yarrel|13 years ago|reply
But yes, long parameter lists (whether represented as argument structs or not) generally indicate a problem.
[+] [-] hnriot|13 years ago|reply
[+] [-] pathdependent|13 years ago|reply
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 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
[+] [-] peeters|13 years ago|reply
Examples like Guava:
Or Hamcrest: Or Rest-Assured:[+] [-] bartonfink|13 years ago|reply
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
[+] [-] jebblue|13 years ago|reply
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
[+] [-] SeanLuke|13 years ago|reply
[+] [-] erode|13 years ago|reply
[+] [-] x3eme|13 years ago|reply
[+] [-] jebblue|13 years ago|reply