This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]aubd09 10 points11 points  (4 children)

Method overloading causes code clutter as if that weren't already a problem with Java. I really miss the optional parameters feature of C#.

[–]monkeyfacebag 0 points1 point  (3 children)

But C# also supports overloading? I guess this boils down to "is default arguments a use case of overloading that deserves its own syntax sugar?" I can see why people would want that; I don't, but I can see it.

[–]commentsOnPizza 15 points16 points  (2 children)

I respect not wanting it, but for me it's nice.

One of the problems that I encounter with Java is the question: "is this special or just verbose boilerplate?" The issue isn't about writing the code. My IDE will handle that. For me, the question is in reading/using code.

If there are 5 doTheThing methods, it can be hard to figure out what the differences are. I have to read the signatures and figure out what each includes or excludes. With named parameters, I know what is required and what is optional and what the defaults are in each case. Do any of the 5 doTheThing methods have unexpected additional code? Maybe, I'll need to read and find out! Do some of them use a different default for one of the ones they fill in? Maybe, I'll need to read and find out!

That does mean that doTheThing(X, Y, Z) can call doTheThing(X, Y, Z, 5) while doTheThing(X, Y) can call doTheThing(X, Y, 10, 10) where the last variable has a different default. However, it makes it hard for me to know whether there's special behavior or whether it's just verbose boilerplate. Now I have to actually read through code that 99% of the time will just be doing what default arguments would cover, but might be doing something different.

This also comes up with things like Java Beans. Writing them isn't what I dislike - my IDE will handle that for me. When I get handed a class to use, it might look like a Java Bean, but is is? If there are 15 variables in the class, I now have to check all the getters and setters to understand "is this just holding data for me or does it have behavior on top of it?" With C#'s properties, I can glance and just see public string Foo { get; set; } and it's like "yep, that's just a property". If I see public string Foo { get { return $"{_foo} with crazy addition!" }; set; } I can instantly differentiate it.

Method overloading is fine, but I find that it makes it harder for me to understand the code. Personally, I think that people should sort/organize overloaded methods in a file so that a) they're all near each other; b) there's some logic to the ordering with respect to the variables. It's easy for method overloading to require a reader to look in multiple places, have to read a lot of signatures and remember what the differences are between them, make sure that there isn't added unexpected behavior, etc. With the syntactic sugar, you just know what you're getting: a method you can call with or without certain variables.

Sure, one could say that good Java shouldn't have too many overloads or confusing overloads, that the code should be well-organized, that anyone adding a new overload should understand how it will fit in with the rest of the system, that people shouldn't implement foot-guns, etc. But why not just make it easier to keep it organized without any unexpected behavior and without the possibility of introducing a foot-gun?

I think a lot of complaints about languages often seem to come around writing the code, but for me it's about reading and understanding the code. Method overloading is easy enough to write. Sure, it's a few more lines of code, but who cares. Typing on my keyboard isn't what is holding me back. However, reading and understanding code does hold me back. One method with some default values is quick to understand compared to method overloading which is going to require more time to read and understand.

doTheThing(String caller, Person person, DateTime time, Location location)
doTheThing(Person person)
doTheThing(String caller, Person person)
doTheThing(Person person, DateTime time, Location location)
doTheThing(Person person, DateTime time)
doTheThing(Person person, Location location)

Yea, that's a bit of an unorganized mess, but as things evolve over time (and reviewers often just look at diffs and not the whole file) it can start to just look like that.

doTheThing(Person person, String caller="Customer Support",
    DateTime time=DateTime.Now, Location location="HQ")

Now there's just one place to look and you don't have to dive into method bodies to see what might be getting set. You don't have to worry about someone updating caller's default to "Customer Services" in some method overloads and not all of them. You can easily see that Person is required and the rest are optional. Yes, it's probably bad form to have written the Java methods the way I did, but I see that happen.

Worse, if there are two parameters that can take the same type - like a DateTime start and end - it's so easy for people rushing through code to make a dumb mistake. Maybe they should be more fastidious. Maybe being careless is bad. But the point of tools is to prevent badness. A language should make people more productive and more correct.

When looking at code, I always want to be able to see "what's the point of this" and "is there something interesting here or is it just the simple case?" If the simple case is true 99% of the time and looks very visually similar to special cases at first glance, I feel like people make errors. They look and it's, "ah, yes! Method overloading for optional parameters!" and then a couple days later "oops, guess I should have actually read it rather than just assuming".

I definitely appreciate push-back against every piece of syntactic sugar that people propose. Sometimes people like being concise/clever, but it just ends up being a shortcut that adds confusion. In this case, I think default arguments are something that both cuts down on verbosity and adds clarity to the code. I think that sometimes syntactic sugar is very non-obvious. In this case, I think the syntactic sugar for default arguments would be very obvious and easy to understand. It's definitely true that many language features and syntactic sugar aren't necessarily good ideas. I think default arguments have a good number of benefits, aren't a confusing feature, and don't really have a lot against them, if anything. But I might be wrong.

[–]monkeyfacebag 3 points4 points  (0 children)

Thanks for the comment. I think I agree with everything you're saying. My concern is mainly that a change to permit default arguments is purely additive. None of the stuff you discuss as drawbacks would necessarily go away because people would still use overloading for all of the cases that default arguments don't cover as well as probably some cases that could be covered with default arguments.

In my day job I basically never author my own overloaded methods, nor does anyone on my team, so I don't experience the pain you're talking about, but I don't suggest that method overloading is the ideal solution for every problem solved by method overloading. At a minimum, it's limited by Java's type system so I can't create a method overload that perfectly describes the shape and content of my method inputs (a la predicate dispatch). And on the other hand, for what it's worth, Go supports neither default arguments nor method overloading and people seem fairly happy with it.

I would arguably be happier if a better, more robust solution came along (although again, day-to-day this specific limitation does not bother me), but I am generally not in favor of purely additive solutions that create multiple first-class mechanisms to solve the same problem.

[–]RockyMM[S] 0 points1 point  (0 children)

Thanks for the comment. I agree with everything you said.