Why is trying to access the null property throw an exception in some languages?

What really bothers me the most in some programming languages ​​(e.g. C #, Javascript) is that trying to access the null property throws an error or exception.

For example, in the following code snippet

 foo = bar.baz; 

if bar is null , C # will NullReferenceException unpleasant NullReferenceException , and my Javascript interpreter will complain about Unable to get value of the property 'baz': object is null or undefined .

I can understand this, theoretically, but in real code I often have somewhat deeper objects, like

 foo.bar.baz.qux 

and if any of foo , bar or baz is null, my codes are violated. :( Also, if I evaluate the following expressions in the console, the results seem to be inconsistent:

 true.toString() //evaluates to "true" false.toString() //evaluates to "false" null.toString() //should evaluate to "null", but interpreter spits in your face instead 

I absolutely despise the code to handle this problem, because it is always verbose, smelly code. The following examples are not far-fetched, I grabbed them from one of my projects (the first in Javascript, the second in C #):

 if (!(solvedPuzzles && solvedPuzzles[difficulty] && solvedPuzzles[difficulty][index])) { return undefined; } return solvedPuzzles[difficulty][index].star 

and

 if (context != null && context.Request != null && context.Request.Cookies != null && context.Request.Cookies["SessionID"] != null) { SessionID = context.Request.Cookies["SessionID"].Value; } else { SessionID = null; } 

Everything would be much simpler if the whole expression returned null , if any of the properties were null. The above code examples could be much simpler:

 return solvedPuzzles[difficulty][index].star; //Will return null if solvedPuzzles, difficulty, index, or star is null. SessionID = context.Request.Cookies["SessionID"].Value; //SessionID will be null if the context, Request, Cookies, //Cookies["SessionID"], or Value is null. 

Is there something I am missing? Why don't these languages ​​use this behavior instead ? For some reason, it's hard to implement? Will this cause problems that I don’t notice?

+6
source share
5 answers

Could you cause the problems that I am missing?

Yes - this will cause a problem when you expect non-zero values ​​to be there, but due to an error you have a null value. In this situation, you want an exception. Failure to remain silent and save bad data is a really bad idea.

Some languages ​​(like Groovy) provide a null safe dereference operator that can help. In C #, it might look something like this:

 SessionID = context?.Request?.Cookies?["SessionID"]?.Value; 

I believe that the C # team considered this in the past and found this problematic, but that does not mean that they certainly will not revise it in the future.

+8
source

And then, if the tail of this is a method call that returns bool, then what? Main.Child.Grandchild.IsEdit() and bool IsEdit();

I think it would be better to have a "null" instance that returns the default behavior (this is called a null object pattern ).

Thus, for others who expect null to indicate a problem, they get their exception, but if you know that the default object is acceptable, you can implement this and not worry about it. Both cases are then resolved.

You can get all the "null" objects from INull, put them in a hash against their class name, and then refer to this if the member is NULL. Then you can control the default implementation of "null" (which would be acceptable if the object is "null")

In addition, null objects can throw exceptions if they are accessed, since you know that you have accessed them, and choose when this will be normal. That way you can implement your own "null object exception".

If they will support any language support for this, it will be either for everyone, in all directions for the unit of translation, or for an object by object with a qualifier (the last preferred option), at this point it will not be the default, and you could already implement the default null instance.

+2
source

May I suggest that if you need to verify that there are many zeros, you are badly structuring your code. Obviously, since I do not have your code, I can’t say it definitively. I would suggest you split your code into smaller functions. Thus, your code should only check one or two zeros at a time and may have more control over what happens if something is invalid at some point.

+1
source

In general, foo.Baz means "on an instance of if foo, run the baz element". It can be a dynamic language, a virtual member, or something else, but we have not completed the first step in the premise: there is no instance.

What you trimmed is an operator to access null values. Quite rarely, and frankly, I do not agree with your statement that this leads to smelly codes (although I can say that you request too many levels in one expression to be healthy).

Likewise, I do not agree that null.toString() should return "null" - IMO, this is normal for this to fail. Handling a null value access as β€œnormal” is inherently incorrect IMO.

0
source

Is there something I am missing? Why don't these languages ​​use this behavior instead? For some reason, it's hard to implement? Will this cause problems that I miss?

When the variable is null , when not expected, the language you mention is not suitable before. This is the central concept when creating properly working programs.

The parameter would have to hide the null pointer problem, and the program would execute another line, but probably a failure later or even worse would lead to an incorrect result!

Also, trying to fix the error, it is easier to fix it if you immediately throw a NullReferenceException and the debugger shows you the line on which to start the search. Vague symptoms would be an alternative - much harder to debug!

This is very common for a program with null when you shouldn't. In the above examples, means null . The answer is that it does not mean anything. As a code reader, I would suggest that the author has forgotten something.

Typically, the best solution is to introduce a small, which I call a "null object", which can be returned instead of null . In your example, the class "NoDifficulty" or "UnknownDifficulty" may possibly be returned to get the result at the end - pure code.

0
source

Source: https://habr.com/ru/post/894549/


All Articles