0

Today my college presented to me an argument about not use some primitives that I never heard before. I would like to see what you guys think about it.

We have a class in our project like:

class Order {

    private long id;
    private String name;
    // more fields
}

We have a builder for this class for all the fields.

I always try to use primitive¹ instead of objects to store values, only to evict the possibility of null pointers in the middle of my code, specially as parameters on my methods. You can notice the long primitive in this class too.

But my college said to me that he prefers to use, in this case, the object Long.

His argument: there is a risk to forgot to set the Long value and the default will be 0 (zero), what could bring some problems.

I made the change and not discussed with him about it, because our ids never start with zero, already preventing some mistake about get the wrong Order with zero id.

But I was thinking if there are some another problem that could be prevented not using the primitive in the same line of his logic.

1. I'm aware about the Primitive Obssession. But I don't think that is related of this subject

7
  • Speaking about identifiers, this has been discussed quite a few times already.
    – yegodm
    Commented Mar 21, 2018 at 18:34
  • 4
    The data type constructor should enforce constraints such as this. Using an object which can be nulled, instead of an integer, for the reason you mentioned.... mutable state is bad, nullable mutable state worse. Commented Mar 21, 2018 at 18:38
  • 3
    To be exact, it's shared mutable state that's bad. Commented Mar 21, 2018 at 19:04
  • 3
    You're better off with final primitive fields that are properly initialized, e.g. unconditionally initialized in the constructor.
    – Erik Eidt
    Commented Mar 21, 2018 at 19:04
  • I don't see problem at having 0 or negative IDs. IDs are usually meaningless (I assume yours are too). The problem is that primitives are failing at expressing the constraints related to the IDs. Default IDs or premature IDs can be missleading. Usually, objects don't have ID untill the system (through the proper procedure) provide one to them. If primitives don't allow you to express your domain, then it's a matter of Primitive Obessison.
    – Laiv
    Commented Mar 22, 2018 at 6:44

2 Answers 2

5

If you need a representation for "not set", then Long is a good choice, with null standing for "not set". If that isn't needed, don't waste time and space with the unnecessary boxing and unboxing between long and Long.

However you decide to represent "not set", client code has to check for that special value. No way to avoid that.

Using null is a good choice, as client code that forgets that check will not be able to do any nonsense calculations with the value, but fail quickly with a NullPointerException. Exceptions are your friend showing you unmistakably that something went wrong. And it's quite likely that you get a compile-time warning for client code dereferencing a nullable reference.

Whatever "not set" representation you choose, make sure that it can't be used for any real work, so never use 0 or -1 for that purpose.

And, as @FrankHileman already pointed out in his comment, make sure that only valid instances come out of your constructor, and can never become invalid (e.g. make them immutable).

8
  • 3
    Most ORMs (including NHibernate) view 0 as a primary key value that has not been set, and thus requires an INSERT into the database. So I would see using a long making the most sense. Commented Mar 21, 2018 at 19:12
  • 3
    @GregBurghardt The fact that popular frameworks do it that way doesn't make it a better solution :-(. Commented Mar 21, 2018 at 19:21
  • 1
    Saying "never use 0 or -1...", and disparaging popular frameworks that do, is overly dogmatic.
    – user949300
    Commented Mar 21, 2018 at 20:46
  • @user949300 Frameworks that use 0 or -1 to mean "not set" are propagating a bad practice. Avoid doing this. Ralf is right.
    – Andres F.
    Commented Mar 21, 2018 at 21:43
  • 1
    @user949300 You're right. "Never" shouldn't be used here. Replace with "Never use 0 or -1 until you have the type of experience to be able to know better, and at that point use your own judgement." Hard lines in the sand mean little to those of us who have learned enough to write the rules and not just follow them. To everyone else, this is good advice. The fact that Hibernate uses 0 doesn't sway me whatsoever.
    – Neil
    Commented Mar 22, 2018 at 7:49
0

There's nothing wrong with saying that all valid IDs / handles are positive. That has the advantage that a default-initialized ID / handle will indicate "not set" / "not existant" without any overhead. And it will be quite natural to support it in APIs, exchange- and output-formats without writing any extra-code for handling just that case.
In languages supporting unsigned types, the underlying type would be unsigned to indicate that's the only special value, but unfortunately Java does not allow that.

Could you use a dynamically allocated wrapper instead? Sure, but you lose the natural handling of the sentinel with minimal extra-effort. Also, the wrappers need more memory, and impose extra indirection, whether that's a significant concern for you or not.

7
  • I wouldn't say "nothing wrong" with using magic numbers to represent an "unset" state. I would say that sometimes it is a necessary evil, but in general, explicit unset state makes your code less error prone. It is easy to forget to check for the magic values and treat the number as real, especially using the code months down the line when the magic numbers are no longer at the front of your mind.
    – Shadow Man
    Commented Mar 21, 2018 at 22:04
  • @ShadowCreeper: The nice thing about designating zero as a sentinel value is that in the vast majority of places treating it as special is either a bad idea or just make-work anyway. Commented Mar 21, 2018 at 22:09
  • @Deduplicator Assume for a second you're using an Order instance with erroneously id 0 due to a mistake in your program. So you check for the existence of this order instance in your database and none found (correctly so, as all Orders in your database have postive ids). Since it doesn't exist, you decide to create it, thereby effectively creating Order with id 0. Your assumption that Orders in your database have positive ids is no longer correct, but the error is not immediate. You test it and see no problems, and then pass it to the client a week later. Bug created.
    – Neil
    Commented Mar 22, 2018 at 7:59
  • @Neil You could add a hook to the DB to make sure it doesn't allow creating an order with ID 0. Or you could do that in the DB access layer. Or, you know, as the ID will be an auto-numbered primary-id-column, you leave setting the id to the db to avoid race-conditions. Commented Mar 22, 2018 at 13:51
  • 1
    Or you could simply make the L in long uppercase instead of lowercase. Why do anything more complex? What advantage do you stand to gain by not failing fast?
    – Neil
    Commented Mar 22, 2018 at 13:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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