Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

This question already has an answer here:

So, we've got a guy who likes to write methods that take Objects as parameters, so they can be 'very flexible.' Then, internally, he either does direct casting, reflection or method overloading to handle the different types.

I feel like this is a bad practice, but I can't explain exactly why, except that it makes it more difficult to read. Are there other more concrete reasons why this would be a bad practice? What would those be?


So, some folks have asked for an example. He has an interface defined, something like:

public void construct(Object input, Object output);

And he plans to use these by putting several in a list, so it sort of builds bits and adds them to the output object, like so:

for (ConstructingThing thing : constructingThings)
    thing.construct(input, output);
return output;

Then, in the thing that implements construct, there is a rickety reflection thing that finds the right method that matches the input/output and calls it, passing input/output.

I keep telling him, it works, I understand it works, but so does putting everything into a single class. We're talking about reuse and maintainability, and I think he's actually constraining himself and has less reuse than he thinks. The maintainability, while probably high for him right now, will likely be very low for him and anyone else in the future.

share|improve this question

We're looking for long answers that provide some explanation and context. Don't just give a one-line answer; explain why your answer is right, ideally with citations. Answers that don't include explanations may be removed.

migrated from stackoverflow.com May 14 '13 at 17:14

This question came from our site for professional and enthusiast programmers.

marked as duplicate by gnat, Jimmy Hoffa, Martijn Pieters, 9000, Bart van Ingen Schenau May 15 '13 at 8:30

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

52  
If he insists on programming Java as if it were Python or Ruby, he shouldn't be programming in Java. –  user16764 May 14 '13 at 18:00
10  
Personally, I see this as a variant of 'stringly-typed' code - with largely the same downsides. –  Clockwork-Muse May 14 '13 at 18:40
3  
Sounds like the sort of code that makes you feel cheap and dirty and stings the eyes... :( –  Robbie Dee May 14 '13 at 19:43
4  
@Mark: I'm betting he's seeing a lot of methods like AppendNumberToString(Object, Object) instead of AppendNumberToString(String, Int). Obviously, if that method is public, there's no information about which parameter is supposed to be provided first. In the second case, the method is self-documenting. –  Michael Blackburn May 14 '13 at 19:48
6  
I usually see people trying to write python as if it was Java, not the other way round... –  Bakuriu May 14 '13 at 20:43
show 12 more comments

18 Answers 18

up vote 87 down vote accepted

From a practical point of view I see these problems:

  • A bloat of possible run type errors -- unless a lot of dynamic type checking which could be avoided with the Java included strong type checker.
  • A lot of unnecessary casts
  • Difficulty understanding what a method does by its signature

From a theoretical point of view I see these problems:

  • A lack of contracts of the interface of a class. If all parameters are of Object type then you aren't declaring anything informative to the client classes.
  • A lack of overloading possibilities
  • The incorrectness of override. You are able to override a method and change its parameter types thus breaking everything which is inheritance related.
share|improve this answer
4  
i misread your second point as "a lot of unnecessary cats". I was going to query which cats would then be necessary but realised none of it made sense. –  bharal May 15 '13 at 12:55
add comment

The method violates the Liskov substitution principle.

If a method accepts a parameter of type Object, I should expect that any object I pass to the method will work.

What it sounds like is that only certain subclasses of Object are allowed. The only way to know which types are allowed is to know the details of the method. In other words, the method is less flexible than advertised.

share|improve this answer
14  
Yep - pretty much all the SOLID principles have been drop-kicked out the window here... –  Robbie Dee May 14 '13 at 19:48
1  
This does not violate any such principle, unless you're prepared to defend the argument that all languages with typeless variables violate Liskov, including languages that Liskov herself was working with when she came up with that. –  Kaz May 14 '13 at 20:31
5  
@Kaz, what do you mean? A language with weak typing is not typeless and I don't think Liskovs point has anything to do with compiler type checking. If I create a Ruby method called def add_user(user), it should be fairly obvious that you cannot throw a Message instance, Hash or File handler into the method - the method presumably expects a User instance. Whether or not a compiler enforces this is irrelevant. However, if I define def construct(object), I would expect the method to handle every imaginable object... which it obviously does not according to OP. That's a violation. –  Niels B. May 14 '13 at 20:52
3  
Okay, it seems we don't disagree then. Any method that by, its' signature, claims to accept something it doesn't, is a poorly programmed method that violates Liskovs substitution principle. construct(Object input, Object output) must take accept any subclass of object - meaning every possible parameter except null. –  Niels B. May 14 '13 at 22:21
show 11 more comments

I'd consider the following direct implications:

Readability

I guess working with him is not exactly the most pleasant experience in the world. You never know what the type is going to be in the end or what happens to the parameters. I doubt you appreciate wasting your time with that.

Type Signature

In Java everything is an Object. So what does that method do in the end?

Speed

Reflection, casts, type checks etc all contribute to a slower performance. Why? Because in his opinion it makes things flexible.

Against nature

Java has been strongly typed since birth. Tell him to start writing JavaScript or Python or Ruby if he wants a dynamically typed dialect. His background is probably strongly based on one of them.

Flexibility

To use the same term as the colleague in question, Java has already figured out flexibility long ago. There is no point to look at it with the horse glasses put on by a dynamically typed language.

Interfaces, polymorphism, covariance & contra-variance, generics, inheritance, abstract classes and method overloading are just a few of the things that contribute to the so called "flexibility". Flexibility is given by the fact that it is trivial to specialise virtually anything from any given type to another.(The usual case meaning specialising a direct upper type or lower type).

Documentation

One of the main goals of programming is to write reusable and stable code. How does the documentation of your example look like? What is the learning time for another developer before being able to use that stuff? I would suggest your guy to write self-modifying assembler code and stay responsbile for it.

share|improve this answer
add comment

There are a lot of good answers here already. I want to add a secondary thought:

This pattern is most likely a "code smell."

In other words, if you need to pass an Object to your method for "ultimate" flexibility, you most likely have a very poorly defined method. Having strongly typed parameters indicates a "contract" to the caller (I need things that look like "this"). Being unable to specify such a contract most likely means that your method does too much or has a poorly defined scope.

share|improve this answer
8  
This is the coder equivalent of microwaving fish curry. –  Michael Blackburn May 14 '13 at 20:14
2  
@MichaelBlackburn: ??? I don't understand that comment ??? What's so special about microwaving fish curry? Googling for it I only get interesting (if you like fish) recipe's and even video's. –  Marjan Venema May 15 '13 at 6:22
3  
@MarjanVenema Microwaving a fish curry generates a lot of fish smell very quickly. –  Jonathan May 15 '13 at 7:07
1  
@Kaz Type casting in no way makes Java "more dynamic". It just hides the types hardcoding inside the method, instead of making types explicit in the method's signature, making the code more brittle and harder to understand. How is that more dynamic, or a good thing? –  Andres F. May 15 '13 at 13:12
1  
@Kaz Disagreed. Hardcoding the type casting in your method is not like letting a language (such as Python) handle it. Besides, if your method is going to crash and burn because the typecast was incorrect, how is it more "dynamic"? You are subverting Java's compile-time checks, and getting nothing in return. –  Andres F. May 15 '13 at 17:52
show 4 more comments

It takes away the type checking that the compiler does and can lead to more runtime exceptions when the object is cast to the concrete type. Thus, the end-user will see the unhandled exception, unless the invalid casts are all caught and properly handled.

share|improve this answer
2  
This... He is throwing away static type checking. It means that the program will fail at run time rather than compile time. That's a bad thing. The language has types. Use them. To ignore that is like calling all your variables var1, var2, var3 etc. Sure it will work but it's not a good idea –  JohnB May 15 '13 at 7:35
add comment

I agree with the other responses that this is generally bad practice.

There is one specific case where I find passing an Object may be superior: when you are eventually dealing with Strings, e.g. if you are creating XML or JSON. In that case, instead of something like:

public void addAttribute(String s) { 
  //... add s to the XML
}

I prefer:

public void addAttribute(Object o) {
   String s = String.valueOf(o);  // perhaps check for null explicitly
   // now add s to the XML
}

This saves endless String.valueOf's in the calling code. Also, it works nicely with vararg's. And, with autoboxing, you can pass ints, floats, etc... Since all Objects have a toString(), this, arguably, does not violate Liskov etc...

share|improve this answer
3  
+1 for showing by example one of the few times to do this - thus being the exception that proves the rule. –  fluffy May 14 '13 at 21:01
show 3 more comments

Being flexible and able to handle multiple types of data is exactly what method overloading and interfaces were created for. Java already has the features that make handling these situations simpler while guarenteeing compile time safety via type checking.

Also, if it is impossible to narrowly define what data the method operates on, then that method may be doing too much and needs to be decomposed into smaller methods.

I like a rule of thumb I've read about (in Code Complete I think). The rule states that you should be able to tell what a function or method does just by reading its name. If it is really difficult to clearly name a function\method using that idea (or have to use And in the name) then the function/method is really doing too much.

share|improve this answer
add comment

yes. java is supposed to be strictly typecasted . But having Object as parameter will virtually break this rule. Moreover, it will make your program more bug prone.

And that's the one of the top reasons, why generics were introduced.

share|improve this answer
add comment

First, if you pass the parameters as the concrete object, any error of using the wrong object (instance of a non expected class) will be detected in compile time, so will be faster to fix. In the other case, the error will be shown at runtime and will be harder to detect and fix.

Second, the code of checking the real class of the instance, reflection, etc, will be slower than a direct call

share|improve this answer
add comment

The rule that I follow is... parameter definitions should be as specific as needed by the method, and no more and no less.

If all I need is to iterate an enumerable, the param is defined as an enumerable, not an array or a list. This allows any type of enumerable to be used, avoiding converting to a specific type.

I also will not define it as an object because I need an enumerable. Any object that is not an enumerable will not work in this method. It's confusing to read a method signature and not know what it means, and only run-time testing can find the error.

share|improve this answer
add comment

What he does is throwing away all advantages of having a static type system.

Simply: It's much less clear to what such methods do, both to a compiler and to people reading the code.

One of the biggest reasons for a static type system is to have compile-time guarantees about what a program does. The compiler can check that a piece of code is used correctly and if not, issue a compiler-time error. Methods like you're colleague is writing are much more prone to run-time errors, because compiler-time checks are missing. Be prepared run-time errors and for writing a lot more tests.

Another big problem is that it's not at all clear what a method does. Reading such a code, maintaining it, or using it is a big pain.

Java added generics to give stronger compile-time guarantees about code, Scala is going even further with its functional approach, and sophisticated type system with covariant and contra-variant types. Your colleague is going backwards against this line of development, throwing away all its advantages.

If he used properly typed, overloaded methods instead, he (and you all) would gain:

  • Compiler time checking for correct usage of those methods.
  • Clear indication what combinations of arguments are allowed and what aren't.
  • The possibility to properly and separately document each of these combinations.
  • Code readability and maintainability.
  • It would help him to split his methods into smaller parts, which are easier to debug, test and maintain. (See also How to convince your fellow developer to write short methods?.)
share|improve this answer
1  
@Kaz Yes, I respect their arguments, but Java is then a very bad choice for such an approach. –  Petr Pudlák May 14 '13 at 21:48
2  
@Kaz: I think everyone can agree that a static type system has some advantages. Not everyone agrees on whether these advantages outweigh the advantages of the opposite approach; but this developer isn't getting the advantages of the opposite approach. (No ducktyping, no implicit typing, no terseness.) He's sacrificing all of the benefits of static typing, while shedding almost none of the costs. –  ruakh May 15 '13 at 2:54
1  
@Kaz That's absurd. If you program in Java, follow Java conventions. If you program in Python, follow Python's. And not all of us think the arguments for dynamic type systems are "solid". –  Andres F. May 15 '13 at 12:06
1  
@Kaz If you want to write experimental code against the conventions and assumptions of a language, by all means do it... on your own. If working with a team, follow the conventions. It's as simple as that. Also you are turning this into a debate about creativity, which is absurd. If you use a hammer as a hammer, instead of as a screwdriver, you are not being any less creative; you are using a tool for its best job. –  Andres F. May 16 '13 at 12:14
1  
@Kaz Nope. In fact, since the advent of generics in Java 1.5, it's frowned upon to write code that expects Object arguments, except in very specialized situations. Before, due to a limitation of the language, containers and collections had Object elements which you were forced to cast to the appropriate types -- an error prone task, and not very "dynamic" either since the typecasts were explicit! –  Andres F. Sep 20 '13 at 18:35
show 6 more comments

I actually had to work on a package like that once, it was a GUI package--the designer said he came from a Pascal background and thought passing around nothing but a base class everywhere was an awesome idea.

In 20 years, working with this toolkit was one of the most annoying experiences of my career.

Until you have to work with code like that you don't notice how much you rely on the data types in your parameters to guide you. If I said I had a method "connect(Object dest)", what does it mean? Even if you see "connect(Object website)" it's not much help, but "connect(String website)" or "connect(URL website)" you don't even have to think about it.

You might think "connect(Object website)" is a GREAT idea because it can take a string or a URL, but that just means I have to guess which cases the programmer decided to support and which he didn't. At best it moves most of the trial and error part of development from coding time to compile time, at worst it it make the whole development process muddy and annoying.

I (And most Java programmers, I believe) constantly figure out API call chains by examining a group of parameters to constructors to see which constructor to use, then how to build the objects you need to pass until you get to objects you have or can make--it's like putting a puzzle together instead of searching crappy documentation for incomplete examples (my pre-java experience with C).

Although building code like a puzzle seems ad-hock, it works amazingly well--all the time.

I know this has been answered, but this was an annoying enough experience that I really felt motivated to make sure as few people as possible need to go through it again.

share|improve this answer
show 4 more comments

To give something a type give:

  1. Users an interface to code to with a semantic description.
  2. Compilers an interface to parse from to allow their optimizers to increase code execution time or shrink code size more easily.
  3. Early(static) binding which catches code errors early in the development cycle.

Using just an object conveys almost no information, thus removing all of these features that were put into the language for the reasons listed above.

Also, the type system was designed for flexibility with its is-a relationships allowing for all of these conditions. So use it to your advantage. Don't waste it by making unmaintainable code.

There may be a particular reason to do something like this at a particular time, but to do this it this generically all the time is poor practice. If you are doing it, get others to look over the problem and see if it can be done another way. In the majority of cases (99.999%) it can be.

In that 0.001% that it can't be, at least you are all on board and know what is happening (though you probably just need some fresh eyes on the problem).

share|improve this answer
add comment

Yes, this is poor practice because it makes no guarentee that the method will be able to do what it needs to for any particular input passed in. The goal of making a method that is widely useable is not a bad goal, but there are better ways to accomplish it.

For this particular case, it sounds like a perfect situation for the use of interfaces. An interface would ensure that objects being passed to the method provide the needed information and allows the casting to be avoided. There are some situations where this won't work well (like if it has to work with either sealed or base classes that you can't add an interface implementation to), but overall a method should only take input that is valid for it as parameters.

share|improve this answer
add comment

Great in-depth answers so far, I really have to say that before even getting into high level philosophy and methodology, they are being lazy, short and simple.

They are not providing good information in their code for others to maintain and understand, and they are going against the design of the programming language at hand. I love PERL, I love Objective-C. I do not however make efforts to bend Java, C#, or C++ for that matter, toward my preferences at the expense of having maintainable, readable, and efficient code.

Yes, if they need to change how a function works, or what the inputs are, they saves a few line changes here and a few refactoring steps. However, the cost to others having to maintain the code is greater, not to mention most modern IDEs such as eclipse and Xcode can handle doing the refactoring automatically with a simple right click command. Furthermore, as others have mentioned, the processing cost is increased with each cast, with each unknown object type that's passed, and I imagine basic built in speedups that runtime would perform by knowing the proper classes are also thrown out the window.

Syntax sugar is always better than salt for the developer, but a balanced diet of both ensures the health of the project and others involved (customer, application, other developers, etc.)

share|improve this answer
add comment

There is no problem with this. In languages that do not have typed variables, this is what happens in every function. Formal parameters are just values, and the type is in the object that is passed, not in the formal parameter.

People Get Stuff Done (TM) in Lisp, Python, Ruby, ...

Though you benefit less from compile time type checking, you also suffer less from compile time type checking.

The real solution is to use some dynamic language that targets the Java virtual machine, instead of writing ugly Java code in which every third identifier is the word Object.

I does make sense to have a completely generic function called construct which takes arbitrary objects.

I think I would enjoy collaborating with this programmer. It would take some of the sting out of using a bletcherous programming language.

Note that this type of code occurs in C in the implementation of the run-time support for dynamic languages implemented in C. E.g. you might see something like this in a Lisp implemented in C:

/* Map each object in a list through a function, in order to produce
   a list of the return values. */

val mapcar(val function, val list)
{
   val iter = car(list);
   val out = nil;  /* nil is really a null pointer */

   for (iter = car(list); iter; iter = cdr(iter))
      push(funcall_1(function, car(iter)), out);  /* push is a C macro */

   return nreverse(out); /* destructively reverse list */
}

The val type is actually something like:

typedef struct object *val;

and struct object is a complicated structure that overlays various kinds of type information for various kinds of objects.

I developed a very nice little programming language, whose internals are all done in this style, which I deliberately kept as clean as possible: more so than in the internals of some other language implementation which take a similar approach.

In this style, amazing things are possible in a small amount of C code.

share|improve this answer
show 8 more comments

Assume for a minute that "Object guy" has reason for using a generic "loosely" typed object. We do not know his reasons, but it reminds me of the value of using inheritance and Generics (Templates). In the off chance that Object-guy is actually trying to make sense, this is the sense he might be trying to make:

I always base my objects on a single base object. This base object handles additional duties like exception handling, logging, profiling, and garbage collection.

I always base mathematical objects (those that might support mathematical operators) on a single base class. This helps provides utilities to handle exceptions in the event a derived class does not handle a certain operation. For example, using a Taylor series in the event an explicit representation for a function is not available.

So I do not know Object-guys reasons are: perhaps they are just because he like dynamic typing offered by other languages. But perhaps he is trying to appreciate the value of inheritance.

He may also want to explore Generics (Templates). I used them in C++ to define two, three, and four dimensional images, where the pixels can be bytes, ints, floats, complex, or spectra. I had to do a fair bit of casting, but the pay-off was significant in terms of separating the geometry of images from the computation of pixels.

share|improve this answer
show 1 more comment

Don't forget that this is a good pattern for languages like JavaScript which don't support passing parameters by name. Consider a function

function dialog( message, cancelButton, okText, notOkText ) { ... } 

which has to be called like

dialog( "...", true, "...", "..." );

When you study the client code, it's not easy to remember the meaning of, say, the third parameter of the call. The readability of the client code suffers. Therefore, it is better to declare it with a param object

function dialog( options ) { ... }

which enables you to call it with named parameters:

dialog({ 
  message : "...",
  cancelButton: true,
  okText: "...",
  notOkText: "..."
  })

Principle: We should reduce the number of parameters of a function (zero is excellent, one is frequent, two and more should be rare)!

share|improve this answer
10  
Java is to JavaScript as car is to carpet. The question is about Java. How does any of this answer apply to the question? –  user16764 May 14 '13 at 20:34
1  
I LOOOOVE the car to carpet analogy :D –  SinisterMJ May 14 '13 at 22:57
show 4 more comments

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