3

I wanted to follow up on this previous question I asked related to @Laive comment, but I couldn't think of an excellent way to do so without asking another question, so here we go.

With the previous question in context, many users suggested the approach of creating a parameter. The object for a method that has many parameters, others pointed out that plans probably should not have many settings.

I am assuming that the technique has been engineered correctly, and it's been decided that the method should have a reasonable number of parameters, but not only 1 or 2).

Creating a parameter object, if you have optional parameters, needs to have some way in your object parameters. Declaring that a certain as the optional parameter is "not there", and then in your code, you would have to handle that case.

I researched blogs and stuff on the topic, and it seems like it is not preferred to have a method signature that accepts nulls as a flag for "optional value not present".

What is the difference between a param object with an optional field which has a "field not set" value, and a method with explicit parameters for which null is a valid value to represent "optional parameter not set", and why is one acceptable and the other not?

  • 2
    As you're dealing with a number of issues in this area, it seems to me like maybe your parameters are really an entity/concept that should be formally made manifest, rather than say, making your clients deal with some loosely/informally associated variables. You might then also consider a builder pattern, to construct such a parameter object/entity. – Erik Eidt Nov 8 at 17:03
5

In general it is a bad idea to use null to indicate an optional value. It is a bad idea whether it is for a return value, an object property, a local variable or any other context. So parameters is just one case of a general rule.

So why is it a bad idea? Two reasons:

  • It is not possible in Java to indicate in the type system if null is allowed or not.
  • The default value for an uninitialized reference is null.

This means a reference can be null for two reasons:

  1. There is a bug and the value was not properly initialized
  2. It is intentionally null to indicate the lack of an optional value

Since the code can't distinguish between the two cases, a bug may go unnoticed because the code cannot distinguish a bug from the legitimate value. Therefore other approaches to indicate optional values are preferred.

Using a parameter-object with nullable properties is not really better though since you have the same issue: You don't know if the property is null due to a bug or intentionally. So I disagree with your premise that this is better.

  • That is a good point, I never thought of it that way; I've used null to represent "optional value not present" in my code a lot without thinking that, in a black box, "null" could be indication of a bug in code flow. – Ertai87 Nov 8 at 22:11
0

The problem with using nulls is that you need to document that null is a valid value, then remember that an object could be null. Also, the person using your method will constantly have to refer to the documentation to see if that parameter could be null.

Instead, if you had a Parameters object, those optional fields could be stored as Optional<Foo> fooParam which forces the user of that parameters class to explicitly check for and deal with missing values:

// this is just sketchy code to get the idea across
class Parameters {
  // if this is specific to one method/class, you could initialize this to the default anyway.
  private Optional<Foo> fooParam = Optional.ofNullable(null);
  private final String required1;
  private final String required2;
  public Parameters(String required1, String required2) {
     // you know what to do
  }

  public void setFooParam(Foo param) {
    fooParam = Optional.ofNullable(param):
  }

  public Optional<Foo> getFooParam() {
    return fooParam;
  }
}



// somewhere else
public void myMethod(Parameters params) {
  Foo foo = params.getFooParam().orElse(DEFAULT_FOO);
  // ...
}

So no explicit checks for null and users of the code don't have to wonder what the params should be for myMethod

  • 1
    But according to the creator of the Optional class, Optional is intended to be used only in the return value for methods, and is explicitly not intended to be used as a parameter. How does this approach not violate that constraint (or at the very least, not obfuscate the code to make it look like the constraint isn't being violated when it actually is)? – Ertai87 Nov 8 at 15:35
  • Furthermore, in your business logic (myMethod in your case), it is true you don't have an explicit null check, but you do have an implicit one (inside Optional::orElse); you're not saving anything except obfuscating away your null check to make it look like you're not doing it when you actually are; I don't understand how this solves the problem. – Ertai87 Nov 8 at 15:37
  • It's not a parameter, it's a field in a class. I guess if you really wanted, you could have the fooParam be just a Foo that may or may not be null and in getFooParam() return Optional.ofNullable(fooParam) . in my opinion, the code isn't obfuscating anything, it's making things more clear by yelling to the world, THIS COULD BE NULL AND HERE'S WHAT TO DO IF IT IS. – Matthew Nov 8 at 15:38
  • 1
    Also, it solves the problem because the implementer of myMethod doesn't have to remember to check for null, the implementer MUST do something about the Optional and it's clearer to the caller of myMethod that the foo param is optional. – Matthew Nov 8 at 15:45
0

I think the main problem with nulls as optional parameters is that it makes code harder to read. For example, let's say I have a method with 6 parameters where the last 5 are optional:

foo("example", null, null, 1, null null);

Looking at that, it's not terribly easy to tell which parameter I am providing and which ones I am not. I have to count and look at the definition of the method to understand what's going on. Really there are two problems, though. Too many parameters is probably the bigger one. Anytime you have a function that takes multiple distinct parameters of the same type (i.e. not varargs), it's more difficult to mentally parse:

foo(1, 2, 3, 56, 77, 99);
foo("left", "right", "up", "down", "charm", "strange");

Since nulls are a valid value for any Object reference, they turn distinguishable parameters into indistinguishable ones. A simple example can demonstrate this last point:

Assume a function with lots of parameters like so:

void drawRectangle(Point center, Float width, Float height, Color fill, Color stroke, Scale xScale, Scale yScale);

An example of all the parameters filled in might look like this:

drawRectangle(point(3, 20), 30.0f, 20.0f, RED, BLACK, scale(0, 100, 0, 1000), scale(0, 100, 500, 0));

This is ugly, for sure. Too much going on but if I can remember that x parameters come before y and that fill comes before stroke, you can pretty quickly scan to see what the width parameter is. I know that something of type Point is the center, the dimensions are Floats, etc.

Now let's assume all of the parameters are optional where null represents a default. This is a little far-fetched for something like this but bear with me for demonstrative purposes:

drawRectangle(null, null, 20.0f, null, BLACK, null, null);

Now, when I look at this, it takes more time to make sense of what is being specified. The type information is gone because null is a valid value for any object type. I see a float in there, but which dimension is it? I need to slow down and probably pull up the definition.

  • 1
    I'm not sure I see how null in this case is any worse than having a method that takes a whole bunch of parameters of the same data type in the first place; you still have to cross-reference the method signature with the argument list to make sense of what's going on. Not to say the latter isn't also a problem, but given that you are prepared to do the latter, I don't see how null really exacerbates that issue. – Ertai87 Nov 8 at 22:13
  • I've added a more detailed example to help illustrate the problem. – JimmyJames 2 days ago

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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