I have generally read that having many (>4) arguments to a function/constructor is a bad practice.

  1. Is this still considered a bad practice? And is there a non-obvious reason?
  2. In something like a Scala Case Class where there may be many fields what can be done to avoid such a construction?

(Not sure if this is best fit for here, SO, or CodeReview)

  • @Downvoter What makes this a bad question? Wrong SE site? – ford prefect Aug 6 '14 at 19:50
  • 1
    I didn't downvote, but it looks like there are two different questions. Is it about constructors with many arguments, or about Scala case classes? :) I'd focus on one. The former sounds like it belongs here; the latter (which is narrower in scope and more technical) could be rephrased so that it belongs more on StackOverflow ("how do I solve this problem with Scala: (the problem)?" – Andres F. Aug 6 '14 at 19:56
  • Yeah it's still bad smell because often those parameters belong together: consider the function IsEnlistAble(Age, Gender), both age and gender belong to a person, the same person, not different persons, so you would make the function IsEnlistAble(Person) that would be much clearer and if requirements change like, only males shorter then 2 meters are enlistable, then you wouldn't have to change the arguments. – Pieter B Feb 6 '15 at 17:26

I have several 'smell' tests for 'best practice'. Some come about through bad implementations, or weak tools. Some help our imperfect minds to create high quality stuff. Some are identified by correlations between code and bugs (though causality might never be demonstrated). So I like to understand what a rule is contributing.

It is pretty clear that lots of parameters can become a usability challenge.

However, lets test against some stiffer criteria.

Lots of systems do CRUD transactions on relational databases.

So, one test is "would this 'best practice rule' effect my codes CRUD transactions in a positive or negative way?"

After all, though you might not like my benchmark, relational databases are intended to represent chunks of the real world in robust, ACID transactional ways.

Building incomplete relationships, that don't represent real-world state, is usually "a bad thing". It creates extra complexity to support it, with no apparent pay-off.

This isn't a license to ignore "proper types". If parts of the constructor or function parameter list contains the values of real meaningful types, representing something relevant in the domain, that has behaviour in the application, then those should be constructed or passed.

AFAIK, all functional languages explicitly provide mechanisms to represent and build 'proper relationships', and that is 'a good thing'.

So I accept that there are some simple, reasonable usability issues, which shouldn't be ignored.

However, in the case of a functional language '>4' does not seem helpful. Immutability is a much bigger 'hammer' to crack problems. For me, correctly representing the state of reality, trumps '>4' every time.

| improve this answer | |
  1. Yes. The number of possible permutations for n arguments scales rather quickly. It's easy to forget the order of the arguments to a function of arity 5. Moreover, there's a good chance some of those arguments are always used together. Wrapping them up makes passing them around easier (and is necessary for returning them from functions.)

  2. Not too familiar with Scala, but anonymous classes would help since the order of the fields isn't important.

| improve this answer | |
  • 1
    The first part of your answer has to be considered in the context of a given language. Languages that support named parameters (including Scala) don't require that the developer remember (or look up) the order of parameters. And for those that don't have named parameters or something similar, the code completion found in any modern IDE provides a lot of help. – Caleb Aug 6 '14 at 19:53
  • @Caleb Named parameters are just a cheap, less flexible version of wrapping arguments in a record; in my mind there's only 1 argument there. Re: IDEs, they help, but you still have to pause and look at the list of alternatives. The less you have to fall back on autocomplete, the better. – Doval Aug 6 '14 at 20:02
  • @Doval - I read the posters "And is there a non-obvious reason?", as asking for non-obvious reasons. It seems obvious that having a lot of parameters creates usability issues. Am I missing the point, or are you simply trying to ensure all the answers are presented so that the question is clear? – gbulmer Aug 6 '14 at 20:33
  • @Doval Note that with Scala case classes, the order of fields matters. – Andres F. Aug 6 '14 at 20:33
  • @gbulmer The definition of "a lot" is non-obvious though. In my opinion, 3 is already pushing it. – Doval Aug 6 '14 at 21:26

Scala case classes are a lot like immutable tuples (plus other stuff irrelevant for this question). I don't find a tuple with more than 4 elements strange, though there is certainly a limit where it starts to become unreadable.

Also, because a case class such as Person(name: String, age: Int) is immutable, some of Java's patterns for building complex objects such as the Builder pattern become difficult to apply. See What is the Scala equivalent to a Java builder pattern? and Type-safe Builder Pattern in Scala.

| improve this answer | |

I've never heard this.

What are you expected to do if you need to pass in both a username and a specific security permission? Should you create a new class that can hold both, populate it, and then send it through to maintain "less is better" in regards to parameters? I can't imagine that this can be true.

Even libraries that are obsessed with performance (jQuery, php, .NET) have multiple arguments in their functions.

I think my answer made more sense before the OP edited their question to only encompass >4 parameters. My answer stands if there are only 2 parameters or so.

If there are >4 parameters...yes, you should reevaluate what you're doing and consider if all of the parameters are actually needed or if a more encompassing object can be passed in.

| improve this answer | |
  • "Should you create a new class that can hold both, populate it, and then send it through to maintain "less is better" in regards to parameters?" There are languages that provide tuples and records out of the box and creating custom types can be done in one line. – Doval Aug 6 '14 at 19:27
  • Would you use 2 Tuples instead of 4 parameters? I would only consider it if Item 1 and 2 in the Tuple were directly related with neither representing an index/key (in which case I'd use a dictionary.) – JMD Aug 6 '14 at 19:33
  • It all depends on whether they're related, but odds are at least 2 of them are. It's not very often that a function needs to manipulate 4+ completely independent arguments. Unless, of course, it's a god function, but then you have bigger problems than remembering the arguments. – Doval Aug 6 '14 at 19:37
  • 1
    Depends on whether the language is statically-typed or not. If it is, it probably compiles down to the same thing. If it's not, then you'll definitely pay some overhead by wrapping it up, though maybe a good JIT can fix that in the long run. Still, if your app has performance problems they probably lie elsewhere. I wouldn't default to bad API choices based on premature micro-optimizations. – Doval Aug 6 '14 at 19:42
  • 1
    Rather than adding EDIT: to your posts to add additional information or attempt to communicate, consider simply editing your post to make it a coherent whole. Everyone can see a detailed, time stamped history of your answer here, so using EDIT: is not necessary. – Robert Harvey Aug 6 '14 at 19:42

The issue is twofold.

In case of functions/methods:

  • Having to pass many parameters is an indication of a non-cohesive design.
  • The method doesn't use the state of the class.
  • If it's a static method in a static utility class, it's OK. Otherwise it's a possible indicator that the method doesn't belong to that class.
  • Even in case of a static method, you can avoid a lot of parameters creating a "parameter object" that is a class with all values needed to pass to the method.

In case of constructor:

  • You can use the "parameter object" I mentioned above
  • Or you could populate the object with setter methods. In this case you should provide "inteligent defaults" so object has a default state to begin with, or throw an invalid state exception if you call a method that requires the object to be fully initialized.
| improve this answer | |
  • 1
    Note that case classes in Scala are a lot like tuples and are usually immutable (so no setter methods). So if Person(name: String, age: Int) is a case class, you more or less have to pass the parameters on construction. Having a PersonParams object would be pointless in this case. What would it be, another case class? In that case, you haven't really avoided the problem ;) – Andres F. Aug 6 '14 at 19:44
  • @AndresF. That is why my question is kind of scala specific but is there a way around this – ford prefect Aug 6 '14 at 19:52
  • If a partial constructed object makes no sense, i.e. it needs 5 values before it makes sense, then constructing an 'invalid' instance just to avoid a 'no more than 4 parameters' rule creates code complexity (to check its own completeness), and hence seems to create complication which would need to be written tested, debugged and maintained. So I think the 4> rule applied to constructors is not appropriate. I dislike "parameter objects" too. I have worked on large apps where their misuse defeated the type system and prevented the compiler helping. Write code that makes sense, and is simple – gbulmer Aug 6 '14 at 19:54
  • @inquisitiveIdiot I'll add the scala tag to your question. – Tulains Córdova Aug 6 '14 at 19:55
  • "setter methods" = "builder", please don't do setters :/ – Boris Churzin Dec 24 '17 at 13:53

Not the answer you're looking for? Browse other questions tagged or ask your own question.