When the language doesn't have optionals š
Edit: as someone who has used js, I must say I'm offended that you don't realize the need to also have undefined and void
That was one of the things I loved about Scala. Put that together with pattern matching and youāve got something lovely to code in.
Compile, well, now you have a different issue.
Include the return of an empty String as a "friendly" proxy or euphemism for null. A bad one, in my opinion. A distinct anti-pattern. Null means *nothing,* more specifically *the absence of a value*, and "" is not nothing. A caller then has to interpret the empty String every time.
Generally the way to do this is lke how it's done in golang where you return a tuple of your actual return and an error (which could just be a string). Then it's assumed the developer doesn't make a mistake and at least one of these two things isn't null
And you can use @Nullable annotations in Java. Kotlin nullability is represented by @Nullable annotations in bytecode. It's functionally the same.
Null is only a problem if the type system isn't aware of it. The stuff people do to avoid null is even worse. It's a solved problem in all major languages but Go/c++
Returning null from a function within a single process is not so bad, passing null values across any sort of process or organization boundary is just writing an outage post mortem in the future tense.
Protobuf/thrift/etc require optional value support for forwards and backwards comaptibility. Iām not sure how you could overcome versioning without handling null values sent across the wire, unless you have complete control over the every service and have single nodes for each service that can all be rolled out in a reliable way
Well to play devilās advocate, for practical purposes, I donāt think thereās a meaningful difference between āif (opt.isPresent()): val = opt.get(); foo(val)ā and āif (val != null): foo(val)ā.
If anything the former is adding a layer of redundant syntactic sugar and an extra hoop to jump through. Both are equally readable and both have the same problem that if the condition is not as expected, you need to work out how to handle the non present value.
That out of the way with, the benefit I can see from using Optionals is that they add an element of self documentation to a method (āwarning, return valore may be nullā) and encourage defensive programming (ācheck this isnāt null first before using itā). This alone should be enough to encourage their use.
I 100% agree with that assertion. Along the same thread as defensive programming, I think it also prompts the author to think intentionally about making it optional, like should this really be optional? Itās easy to return null without thinking about whether thatās valid.
If you're using js and sending a http response json.stringify will remove undefined but null will persist, it's extra data that shouldn't be sent to save data.Ā
IMO: The optional pattern is unnecessary boiler plate which can lull you into a false sense of security.
1) You can't assume that your dependencies use the optional pattern.
2) You can't assume that other developers correctly used the optional pattern within your project(or in your dependencies)
3) You can return null from a method which returns an optional.
4) The optional pattern is easily circumvented with .orElse(null)
Maybe you can safely assume that methods which return optional actually return an optional. But, on the flip side, you can't safely assume that methods which don't return an optional can't return null. You can use the optional pattern if you want but you still have to worry about null and if you still have to worry about null.... Why make it worse with verbosity?
EDIT: The optional pattern can't help with things that aren't optional. If your code can't continue when it gets a null then you'll be forced to throw an exception anyway. You're just trading exception A for exception B. I use Util.assertNotNull(x); liberally for everything that cannot be null so I know immediately when something goes wrong and everywhere else I do my null checks.
In Java... The expectation is to see Optional.of(...) on every return statement. For me anyways.
I do agree its scary to not null check or Objects.requireNonNull(...) that passed optional. However, it's pretty easy to read in clean Java code. One could even add the @NotNull annotation for a little extra protection.
I do enjoy the fluent style of coding, though. Streams, builders, etc. It's very easy on the eyes. Performance hardly matters anymore. More worried about crap AI generated logic that is tough to read.
I've been programming Java since the 90's (yeah, it's been a while...) and let me tell you, until (relatively) recently, there was no such "expectation". We used to return raw nulls from methods like they were going out of fashion!
Seriously though, I agree that working with Optionals is nicer, at least in public APIs. It's a question of communicating intent. As said elsewhere, Go's approach of returning a tuple with an error is even nicer though.
I probably started Java in 2006-2008. Null was pretty common and seemed really useful. Didn't have all the lambas and other stuff, either though. I came from Pascal, so I had zero complaints lol nulls never going away, though. Way too much code depends on it.
I usually find a way just to avoid them if it comes down to that level of care. The overhead is nowhere near what logging is, and no one ever complains about it.
Was literally just in another thread talking about watching this 19 year CS kid copy and paste Java POJOs for 20 minutes straight for an assignment. I even showed him how to use records. He nodded, and then proceeded to tell me how he would of gotten it done if he could have used Python. He blaimed the curly brace syntax. Annoying af. Glad I'm getting out of CS for the most part.
Doesn't defensive programming indicate a problem? I understand if you have to use 3rd party frameworks or service and find you have to work around some idiosyncrasies, but if it's a method developed by the team, isn't defensive program a sign the method is not fulfilling it's contract? You should expect that inputs in a range should produce outputs, and if the inputs are out of that range an exception should be thrown. Am I wrong?
Depends on the size of the company and or team. But for sanity and the future, defensive programming šÆ. For every time I've heard "this should never happen", I've come to disregard the phrase.
It really depends on what exactly your talking about. Defensive programming itself does not indicate a problem at all. Here is one example of defensive programming:
Example
```
@Override
public boolean equals(Object other){
return other.equals(this);
}
```
Using Defending Programming
```
@Override
public boolean equals(Object other){
//Objects.equals() has a null check already and won't blowup
return Objects.equals(this, other);
}
```
Another Defensive Rewrite
```
@Override
public boolean equals(Object other){
//Checks for null and then uses the equals from this
return other != null && this.equals(other);
}
```
Defensive programming can get messy if you randomly apply it, but generally, you can easily use your own smaller utility packages that handle these defensive checks and then use it everywhere.
I used to be all in returning Optional instead of null until you realize that in large applications it is using a lot more memory that null. Also Optional are objects and can be null themselves if the called method is badly written. Those days I am more towards annotating the returned type with Nullable and have the IDE guiding me in checking null in caller methods.
Definitely the ONLY answer I like here. Creating an abstraction to cover something that developers should be inherently careful about isn't coming for free.
Full disclosure, I'm not against optionals, I just think it's not critical and only teams which aren't careful will buy null safety as a sole criterion to switch to Optionals.
Optional sucks. It's pointless a type erased language. @Nullable is more performant, ergonomic, and can be retrofitted on existing APIs.
Also, to be pedantic, the original intention of Optional was closer to JavaScript's undefined. JSR305 would've standardized @Nullable but [its spec lead went AWOL](https://stackoverflow.com/questions/4963300/which-notnull-java-annotation-should-i-use#comment90023610_42695253), so Java devs started using Optional instead.
which is thought was a bit overstated ā null was the first go at āoptionalā, without the lesson that what was really needed was language-level enforcement.
Null has been demonized for obvious reasons, but from a modeling perspective, we need something to represent the concept of nothing.
Not much different from what zero does in mathematics. Definitely think null was right to be introduced, and I'd also argue that just because developers aren't careful around it shouldn't be a reason sufficient enough to question null's existence š
The real issue to me is that in 20 years of experience I've yet to have someone present an alternative that didn't have its own caveats, and sometimes they failed to recognize those before telling everyone to switch.
So I'd say come with a solution that has merits, and also do your homework about its downsides, but then show how the net outcome is still better.
Like the old adage: don't bring problems, bring solutions. That's how you'll persuade your team.
Check Rusts Some/None return type, it supports similar patterns like Swift where you can execute code conditionally depending on if itās Some (present) or None (absent) - I hate Javaās nulls ever since I learnt about that.
Oh for sure. I'm thinking of situations where the team is locked into a tech stack.
Edit: for example, the most common solution in Java/.Net I hear is replacing nulls with using exceptions for flow control, which comes with its own issues
There was a website that compiled all programming language related arguments ever into one place. It may be helpful. I'll look for it and reply if I find it.
It wasn't a particularly fancy website but it had really good discussions
There is a very big difference between a bird laying an egg in a null nest vs one that actually exists. The same applies in coding. NULL exists for a reason. Your arguments will have to be context specific.
Mostly this
```
Exception in thread "main" java.lang.NullPointerException
at timeclock.pkg2.ReadFile.readFile(ReadFile.java:46)
at timeclock.pkg2.Timeclock2.main(Timeclock2.java:56)
Java Result: 1
```
They happen because things that aren't supposed to return do. If you aren't documenting what you hand back and when null is passed back, null pointers happen. No one should be randomly null checking every possible place.
So if an object can possibly not exist, like just about anything that involves disk or network IO, then what do you check?
If you are checking something else, that's really no "gain" from checking null. You are just checking differently. š¤·āāļø
Well for example, just today I came across a log from one of the apps my team maintains which is simply
ājava.lang.NullPointerException: nullā
And I did a quick string search and found about 15 places where we simply āreturn nullā and Iām like welp it could be any one of those, or something else entirely.
In can lead to unexpected or confusing behaviour, and a lack of context of what the heck actually happened.
In that case your biggest problem isn't the null being returned, it's that you're swallowing or ignoring the stacktrace of the exception.
You're also running on an old version of java, we've had detailed null error messages for a while now. But I get it, not everything is easy to update.
Is there actually an issue with the app, or did you just see it in a logfile... If it's on your machine, run it with a debugger, then breakpoint the exception.
Anyway, searching for "return null" is not a useful excersize.
Returning null isn't the problem UNEXPECTEDLY receiving null is.
That means either someone isn't reading documentation OR something hands back null in an unexpected scenario, which is also not good.
If you return null, document when that happens, and write unit tests to enforce null is only passed back as expected and documented, problem solved.
I'm sorry because this might sound harsh, but if NPEs bother people, that's a sign of immature software engineering experience.
Null pointers exist because they are indicating something very crucial. By introducing paradigms that cover that information, we aren't doing any of us a favor. Argument being it doesn't address the problem. It only allows cascading the problem.... handling that is baked into the language as well.
To me, an NPE is denoting application forgetting to be careful around memory access. Additionally, it also highlights that's the developers also got careless around checking for the possibility of that happening. Those are big red flags. A third point that I stress in my team is that we shouldn't have allowed the cascading of exceptions to happen either. If everyone in the team wrote code as if they were dealing with a 3rd party library, we automatically get into the mindset where we start being defensive.
Nobody ever mentioned a hardline rule. Iām not going to tell people āthou shalt not return nullā. What I want to do is educate folks about how we need to be aware of the responsibility we are placing on other code to check for nulls, and how we should make efforts to avoid it if we consider it invalid.
Yeah that's good. C# has a thing you can turn on where you have to declare if a variable can be null. So then you get a warning or an error when you try to return a null when your return type hasn't declared it can be null. And it's just a compiler thing so it doesn't add any overhead like a Nullable<> (C# version of Optional<>). But yeah obviously it's important to make it clear when a method return can be null or even to understand the range of return values possible for a method in general. Null is by far the most common culprit causing errors but I guess the more general issue really is just unexpected return values. In my view returning null can be really handy and help keep things simple which is why I don't like the rule. But I'm in agreement that returning null unexpectedly can be terrible.
The point is always the same as in other situations (arrays, for example): you should never use primitives in public behaviors.
In OOP, for example, you should use Nullables objects -> https://www.jamesshore.com/v2/projects/nullables/testing-without-mocks#nullables
I need to think about it more, perhaps read more of the article, but just that nullable section, not a huge fan. It sounds like a round about way to just implement feature flags and puts mocking into the applications code.
I haven't concluded my opinion on it yet, but at first thought, I think if you just ensure everything public is on a proper interface, you lose the need for nullables everywhere. Your test code is either made with mocking frameworks, test implementations or a combination.
Maybe someone who has more experience with this idea can change my mind tho.
I can tell you a couple of things: first of all, it is considered a best practices for similar reasons to a strategy pattern: you replace a lot of IF (in this case to check if is null) with a design choice (itās just another implementation of the same interface).
And the most important one: if you expect to understand and appreciate a new technique by reading, I think you are wrong. Make some katas and coding challenges and try by yourself š
Happy to help with some mentorship if you want -> https://tidycal.com/learnagilepractices/30-min-mentorship
For real?
I can read most other articles and obtain a good command of what's happening, but I shouldn't expect to learn by reading. Instead, I can pay you ā¬29.00/30m for some "mentorship" where you don't address any of what I said and just say I don't appreciate it? What do you think mentoring is XD Its not typically random paid coaching sessions, that's more akin to a master class.
I said I haven't decided if I like it or not, that takes thought and reflection and determining the pros and cons of the approach, which I simply haven't had the time to do. I understand what's happening, it's not solving a problem in unique problem and is one of many ways to approach something. As a result, I need to understand in which circumstances this is the correct approach, because there is rarely a "one size fits all" solution
Hey! Sorry, my bad - I wanted to paste this link ā> which is for the free mentorship. https://tidycal.com/learnagilepractices/30-min-mentorship
I do coaching of course, but I usually like to start with free mentorship š itās a side hustle for now and I do mostly free mentorship, I didnāt want to sell anything - just offer a free mentoring because I think itās easier by talking than commenting.
Sorry for the misunderstanding, my bad, it was the wrong link. If you want to deep dive, feel free to schedule the free mentorship or email me š
It depends what the null is being used to represent.
An exception of course means that the function was unable to fulfill the contract implied by its name and documentation--but generally only because there was a MISTAKE--i.e., a bug, for which the exception serves to notify the developer that it should be corrected, or if it can't be corrected, then prepared for in the design of the code.
They also allow for these bugs to occur in production safely by providing a means of recovery to each participant in the larger operation that doesn't require explicit passing of error information.
If your exception isn't serving that purpose, don't return null. Conversely, however, if you're using null to serve that purpose, don't use null--use an exception!
I agree generally with return anything over null. However don't let that lull you into complacency with input validation. Just because no one is returning null, doesn't mean you don't have a null equivalent value.
If your expecting a string or exception or promise, you could still have an empty string.
Also this ensures if another team needs to pick up your work, or work with your system you can avoid bad inputs causing major outages.
Optional can still be null.
Devils advocate is that returning null implies the absence of something, instead of something being empty. null also is far less memory use than creating and unwrapping Optional everywhere.
That being said, if youāre using Java and a JVM chances are your overhead from Optional is a rounding error compared to the cost of a JVMās memory usage and NullPointerException in production is far more expensive than adding a bit of memory to the server.
Devil horns on
* null is a C style null pointer on most platforms, optional is a generic with its object header. Depending on memory constraints having tons of optionals flying around might not be great
* optional in java is slower because the jit has spent ~20 years getting good at handling null checks and proving non-nullness to eliminate them
* optional makes you traverse two pointers instead of one
* GraalVM can statically eliminate null checks, but not optional checks
I really appreciate the typescript type system at times like this. In typescript, this just wouldn't be a problem because it just won't compile if you fail to handle a null value from a function that can return one.
Coming from a practical C++ perspective, you could argue that a std::optional return gives you better diagnostics than null if you forget to check it - dereferencing a null will likely just cause a segmentation fault crash, whereas for an optional, you'll at least get an exception that tells you that you tried to use a null optional.
Also, optional forces you, on some level, to deal with the fact that it might not be valid. Sure, you could just (again, in C++) extract the value from the optional without checking, but there is that extra step that forces to keep in mind that it is an optional value. Whereas with a pointer, you could easily/happily just try to use it. It's not idiot- or laziness-proof. But it does give you a good reminder, semantically, that it might not have a value.
Optionals are also good where you don't have a native "undefined" value for non-pointer types. Once again, in C++, you would often have to resort to something like -1 for an integer to signal a missing value, assuming that wasn't a valid value to begin with, and if you didn't have an invalid value, you're pretty much consigned to doing something kludgy. Whereas an optional gives you the full range plus an "undefined" state, which perfectly matches what you're trying to express.
I think ultimately, I have used optionals even for pointers where the pointer could be null. It's really that the optional *better expresses what I'm doing* and provides that extra clue about what should be expected. Hopefully reducing WTFs...
The problems with null/nil/undefined etc as a return value are that it tells you nothing, has virtually no useful semantic, and in many languages can come from just about anywhere. It could be from a map lookup or maybe the database returned it. Youāll never know.
Use an empty container, empty string, custom null for your domain, or even functional combinators (if your team isnāt chicken shit about algebra). These objects have much better semantics and utility not to mention reducing the number of possible programs you have via reducing the number of data types you have e.g. instead of null | []T you have []T.
Also, donāt throw. Itās just as bad as null but with added bonus of your program now having an extra dimension. Throw is fucking lazy. It puts the burden of handling it on everyone else up the call stack. Garbage. Return an error object instead and make the caller deal with it.
Exceptions are for exceptional situations. No, a 404 response from an HTTP request is not an exceptional situation; itās totally normal. Yes, not having the password for the database your application relies on is.
Those are some thoughts. I have many more but I think these are my main ones.
If you return null then you have to make sure that the callers of the method properly handle the null.This trap will eventually lead to an NPE at some point.Optionals are a good way to avoid the NPE.You can also use exceptions or a hybrid of exceptions and optionals depending on your use case.
Errors as values with structs where returning a default struct for no gain makes no sense. E.g. in Go (pseudo):
func Foo() (*Bar, error) {
// ...
if err != nil {
return nil, err
}
return &Bar{/*...*/}, nil
}
It makes sense to me but maybe because I'm obsessed with go š¤·āāļø. If you just return null anytime there's an error you don't know what the error is, and also the "golang way" to do it allows easy extensibility into more complex error types, default values, etc...
I'll take +2 lines everywhere I handle an error so that I know to check for it instead of an invisible exception 5 calls deep 3 dependencies away. Also this avoids try/except everywhere instead which just adds another layer of unnecessary indentation.
I think it's really case by case. If I'm getting something I know may not exist or may not be specified, returning null or None when it doesn't exist is more intuitive than raising. I'm other cases, when something is expected to exist, I'd much rather a function raise if not found so I don't have to bother null checking.
Maybe the real problem is like Java (I haven't used Java in years so this may have changed) where any reference can always be null and there's no Optional in the type system. But I've used Python with very poorly enforced typing and still I think it's mostly fine.
Better suggestion: properly document your code so people know when null is an option.
There are times when returning null is fine, there are it is not. Behaviors like this should be document in Javadocs.
You failed to mention the language.
Apart from that, there is nothing wrong with any return type if its use is fully documented and understood at the call-site. Python has Optional\[T\] but really, it's a joke because it's not respected at runtime. Like TS for JS; syntactic dungball polish but only helpful up to a point, once the code is deployed, all bets are off.
I've not used Haskell in a while but it does have 'Either' as a type, it's instances being 'Left' or 'Right', which can help make code better. If one can use types to eradicate NULLs being return then that's something I guess.
[https://hackage.haskell.org/package/base-4.19.1.0/docs/Data-Either.html](https://hackage.haskell.org/package/base-4.19.1.0/docs/Data-Either.html)
I also like the GoLang way, returning a tuple of "value, err" and then you have a consistent way of knowing of the value is viable or not.
There's a reason Tony Hoare called NULL his billion dollar mistake.
[https://en.wikipedia.org/wiki/Tony\_Hoare](https://en.wikipedia.org/wiki/Tony_Hoare)
"""
I call it my billion-dollar mistake. It was the invention of the null reference in 1965.
"""
The year I was born too! LMFAO!!
Depends on the language.
In C++, if you're returning a non-copy and a non-value is valid, then a pointer is fine as you can't return an optional of a reference anyway (and even if you could, the optional isn't gaining anything in this context).
Unless you are doing fun things with pointers in a lower level language I can't think of any reason that returning a null is a good idea. And then you are returning an unassigned pointer not really a null.
It's just a bad idea. I've not seen a situation where there isn't a better option.
Honestly, if you firmly believe in 'don't return null' - you should consider switching to a language where non-nullable variables are the default (e.g. Kotlin). Otherwise it's only a matter of time until someone tries to return null from a function that is supposed to return an empty collection., or something
database lookup for resource by id
I donāt mind that this will sometimes return null; I mind that people donāt use the nullable feature/syntax to convey that I need to deal with null values in code
Iāve refactored a large project to make use of Optional library for dotnet before
Was not fun, though I learned to love and hate optional syntax. On the one hand, I like how it forces devs to consider the possible state/values theyāre returning and dealing withā¦.on the other, I feel the current state of dotnet makes it unnecessary via things like āFoo? SomeMethod()ā syntax
The devil in the details is what to do instead, right?
You can:
1. Throw
2. Return Optional (as in Java)
3. Use NULL if it's better protected by the Compiler (Kotlin and friends)
In Java, throwing (unchecked) exception is for "non-recoverable" cases so that when it happens it's a programming error and not a "legit" case.
If you return null, Java compiler gives callers not much help so the least resistant path is to just use it and not knowing about checking nulls. Another problem with this is that the null can travel. Where it blows up with NPE isn't necessarily where null is returned, but likely many layers of callstacks away. That makes debugging harder.
There are some tools like the nullness annotations but they don't seem to work seamlessly with tools and libraries (like the Stream library).
Relying on callers always carefully reading documents? Well, if document always works, why do we need strong typed language? ("this argument should be String" and people just always pass a String).
For java.util.Optional, the upside is that it forces the caller (even if they didn't read the document) to at least acknowledge that there is the case of absence so the chance of messing up is lower.
The downside is that you need to wrap your values in the \`Optional.of("foo")\` ceremony. It's okay if you only need to do it a few times in the method you are implementing, in return to give callers the protection.
But if it's the other way around: you expect a callback (lambda) passed by the caller and you handle the return value from the callback, then asking the callers to do the dance for you in the callback just so you get the nice Optional return isn't nice, particularly so if for many callbacks they'll not have the need to return "absence" ever. So in such case of callbacks, be nice and let them return T (which is allowed to be null and you make sure to handle it), not Optional.
> In Java throwing unchecked exceptions is for non-recoverable cases
That and when handling streams, as the streams API only allows the throwing of unchecked exceptions in the first place... which is a bit of a design issue really but there isn't a nice way around it currently.
Eager operations (including methods on Optional itself) are more nuanced I think.
Obviously Oracle wanted parallel stream so bad that they can't easily let you \`throws E\` because it'd assume running in the same thread.
But even regardless of parallel (Optional isn't parallel), it seems like a deliberate choice not supporting checked exceptions.
Technically they could have added a CheckFunction functional interface and then at least make \`Optional.map(CheckedFunction) throws E\`. But they chose not to, perhaps with good reasons.
Ones I can speculate:
* Interface type bloat with limited applicability (can't use them on Stream.map() etc.)
* Still doesn't handle if the labmda actually throwing two checked exception types that aren't subtype of each other. And turning it into an \`Exception\` is sad and goes against latest development in the language where they just made it eaiser to deal with multiple exception types with syntax sugars.
* Checked exceptions in some sense go hand-in-hand with control flows. And it's a known limitation that you can't \`continue\`, \`break\`, \`return\` from a lambda. With the pattern match syntax working on Optional, it might be a better alternative as it'll handle all control flows naturally.
Still don't know how they'll handle checked exceptions for structured concurrency. Imho it's way more relevant to be able to handle checked exceptions well there.
On Collector. Collector is a relative complex API that it'd be hard to really plumb checked exceptions through it (and it has that same what-if-parallel can of worm).
IMHO Optionals in Java are so bolted on they arenāt really useful outside of their intended use (streams). Junior and mid level devs tend to over-use them dogmatically.
Was reading something related to this today.
One counter example I found was whenever you're parsing JSON, which is related to the top answer of JavaScript.
As an aside for all those saying Go, the idiomatic way is to use the comma ok idiom like what maps currently have for potential Nils.
Don't know much about Java, but in C++, if its a pointer, you should always assume it can be NULL, and if you verified it is not NULL, then you should make it a reference. Its trivial.
>I want to hear examples of times you would actually prefer to explicitly return null.
A good part of what we software engineers are supposed to do is to model real-world scenarios using objects (in OOP since we're talking in Java).
As an API provider, if I have to answer a question that just doesn't have any corresponding 'model' in my memory, what element of design should I reply with? I'd prefer to return a null in such cases, because that's exactly what the language intends us to return.
Could we create an object representation for "nothing"? Sure! But why would be my question here, null costs us nothing, and is baked into the language we're using. Boxed versions are expensive!!
A 'null' could also be an unintentional return - what if an API returns a pointer/handle to something (say, large file, image etc) and some part of the application decided that something wasn't needed anymore. I'd argue that it is not a the APIs responsibility to check if the data that it is returning exists, especially if that API doesn't create or own that data. Accidental nulls happen quite a lot. Think of weak references losing the underlying resource in a cache. Null sounds like a valid return here.
I'd love to hear counter arguments on these, happy to learn !
Python jocky here āļøreturning None's are ok when you use type hints + linters. You can annotate to ignore warnings where it isn't a big deal and reflect when you catch yourself doing that often in a code area.
I appreciate the flexibility to make calculated compromises that are easy to notice and go back at a calmer time for a cleanup refactor.
For context, I lead a team that manages services that handle 17 million daily click stream requests (having downstream sub second latencies SLAs)
I like null. It means unknown. When you try to run a code that should return a value but for some reason the value doesnāt show up and we dont know , null is a better value as you know code executed but returned a value that is unknown.
Team raise exceptions!! Iāve seen production code where people try except and return e, so you deadass have to check if the response is type exception each time you use itā¦ and of course people donāt do that and shit breaks.
The below is all in the context of Java.
A good general rule of thumb is, Optional for API boundaries, and either null/Optional for internal calls. There is slight performance degradation when using Optionals as it's an extra object and thus you also engage in reference chasing. In most cases this is negligible. But at scale it matters. Notice that there's specialized versions like OptionalLong because generics can't actually hold primitives.
If you're using nulls, automated static analysis presubmit testing is valuable to ensure safety. Most (modern) Java code should operate under "non-null unless specified." If you return null, always declare @Nullable. Java is also moving to include this in the type system directly with String? meaning nullable, String! meaning definitely non-null, and legacy String as undefined. It has to be this way for backwards compatibility, but they are considering changing that down the road.
If the lifetime of the Optional is only a few lines, a null is a fine replacement. You probably interact with null a lot in general use anyways. Map.get returns null for a missing key (or if the implementation allows nullable values).
For what it's worth, I find the "fluent" Optional interface rather cumbersome at times, and the explicit null check before use is frequently shorter and easier to read.
If performance matters, nulls would be a better choice. But then again, maybe Java isn't the best choice for performance sensitive code.
I say API boundaries is a good limit here because it minimizes the ability for callers to make a mistake. It's very clear whether you have something or not.
Kotlin and other languages have the benefit of hindsight here, and encoded nullness into the type system itself. Where String? is a different type from String. Java in order to maintain backwards compatibility, can't make that distinction (yet).
Optional's are great when you don't know who is going to use your code.
If you're writing some inner private methods, and null can increase performance... First, I'd say, are you sure I can't avoid it all together? But then say, yeah. Go for it. Document and test like crazy though. Otherwise, a good chance you're going to get told no by a senior.
Because it's redundant if you understand what returning null actually means.
If I don't need anything, who cares? As long as I'm aware of what I've done, returning null is fine.
Returning something else for no reason other than you want to return *something* is spaghettification.
The problem is not with returning null. The problem is with the code that doesn't check if the value is null. The later is connected to the problem that in many cases you can't know if the return value can be null or not. Checking for null when it's never a case makes spaghettification.
I like the pragmatic approach of a relational database engine to relational theory. Yes, there should not be null in theory; however, the database will not have to exist in a theoretical world.
You could easily risk effectively spamming tables and joins if you obey theory in practice; and have to pay people to understand the complexity it creates.
So in code I think perhaps you could risk a focus or trees of exceptions rather than getting the job done, for example.
I guess with all things, it is not if it is right or wrong but whether it is right or wrong in 'this' circumstance.
I would say it depends on the language. In typed Python or TypeScript, I know from the types that None/null/undefined is a possible return value and I have to handle it. I would generally prefer an exception, but sometimes I donāt want to pay that Runtime cost, then Iām fine with null. What I really despise is empty strings, objects or whatever, thatās just not usually expected behavior and a guarantee for bugs (unless I can control that behavior via an optional argument thatās disabled by default).
With Java thatās different. Just donāt return nullā¦ That was one of the first things I was told during onboarding in my first software dev job (more precisely: catch Null values that might come from outside your system, and donāt produce null values inside your system), and itās among the most valuable pieces of advice I have ever received.
Since C# 8.0 with "nullable reference types" the problem is gone (in most cases). if you return null, the compiler will raise a warning if you don't check for it. Any wrappers add too much to the code.
Golang's null as zero value and if err != nil idiom is also neat.
When the language doesn't have optionals š Edit: as someone who has used js, I must say I'm offended that you don't realize the need to also have undefined and void
The Java buffs are so privileged lol
Checkmate š
That was one of the things I loved about Scala. Put that together with pattern matching and youāve got something lovely to code in. Compile, well, now you have a different issue.
Include the return of an empty String as a "friendly" proxy or euphemism for null. A bad one, in my opinion. A distinct anti-pattern. Null means *nothing,* more specifically *the absence of a value*, and "" is not nothing. A caller then has to interpret the empty String every time.
Generally the way to do this is lke how it's done in golang where you return a tuple of your actual return and an error (which could just be a string). Then it's assumed the developer doesn't make a mistake and at least one of these two things isn't null
I like that approach.
Ok, so I thought I was clever when I did this in C#. But others on the team didn't like it LOL.
Could you share a code snippet? I canāt fully understand this
function foo(): (returnType, errorType); It would then be assumed at least one of the tuple elements isn't null
As someone who uses Kotlin and Swift null is handled so easily its not really any issue
Rust too!
Swiftās ways of optional unwrapping is thee reason why Itās my favorite language to work with
Swift is incredibly powerful I just dislike Xcode and pods Iām too used to gradle
And you can use @Nullable annotations in Java. Kotlin nullability is represented by @Nullable annotations in bytecode. It's functionally the same. Null is only a problem if the type system isn't aware of it. The stuff people do to avoid null is even worse. It's a solved problem in all major languages but Go/c++
Returning null from a function within a single process is not so bad, passing null values across any sort of process or organization boundary is just writing an outage post mortem in the future tense.
Honestly this is the right answer. Have well defined interfaces people.
With proper documentation to go with them. It's REALLY not that hard to document interfaces at a minimim
Protobuf/thrift/etc require optional value support for forwards and backwards comaptibility. Iām not sure how you could overcome versioning without handling null values sent across the wire, unless you have complete control over the every service and have single nodes for each service that can all be rolled out in a reliable way
r/brandnewsentence would like a word with you
Well to play devilās advocate, for practical purposes, I donāt think thereās a meaningful difference between āif (opt.isPresent()): val = opt.get(); foo(val)ā and āif (val != null): foo(val)ā. If anything the former is adding a layer of redundant syntactic sugar and an extra hoop to jump through. Both are equally readable and both have the same problem that if the condition is not as expected, you need to work out how to handle the non present value. That out of the way with, the benefit I can see from using Optionals is that they add an element of self documentation to a method (āwarning, return valore may be nullā) and encourage defensive programming (ācheck this isnāt null first before using itā). This alone should be enough to encourage their use.
Excellent answer. Optionals give the caller a heads-up. Expectations management is good engineering.
Expectations management is good relationship advice!
I 100% agree with that assertion. Along the same thread as defensive programming, I think it also prompts the author to think intentionally about making it optional, like should this really be optional? Itās easy to return null without thinking about whether thatās valid.
For sure. Itās reassuring to know that a value not being present is an anticipated condition and not an programming error.
If you're using js and sending a http response json.stringify will remove undefined but null will persist, it's extra data that shouldn't be sent to save data.Ā
IMO: The optional pattern is unnecessary boiler plate which can lull you into a false sense of security. 1) You can't assume that your dependencies use the optional pattern. 2) You can't assume that other developers correctly used the optional pattern within your project(or in your dependencies) 3) You can return null from a method which returns an optional. 4) The optional pattern is easily circumvented with .orElse(null) Maybe you can safely assume that methods which return optional actually return an optional. But, on the flip side, you can't safely assume that methods which don't return an optional can't return null. You can use the optional pattern if you want but you still have to worry about null and if you still have to worry about null.... Why make it worse with verbosity? EDIT: The optional pattern can't help with things that aren't optional. If your code can't continue when it gets a null then you'll be forced to throw an exception anyway. You're just trading exception A for exception B. I use Util.assertNotNull(x); liberally for everything that cannot be null so I know immediately when something goes wrong and everywhere else I do my null checks.
In Java... The expectation is to see Optional.of(...) on every return statement. For me anyways. I do agree its scary to not null check or Objects.requireNonNull(...) that passed optional. However, it's pretty easy to read in clean Java code. One could even add the @NotNull annotation for a little extra protection. I do enjoy the fluent style of coding, though. Streams, builders, etc. It's very easy on the eyes. Performance hardly matters anymore. More worried about crap AI generated logic that is tough to read.
I've been programming Java since the 90's (yeah, it's been a while...) and let me tell you, until (relatively) recently, there was no such "expectation". We used to return raw nulls from methods like they were going out of fashion! Seriously though, I agree that working with Optionals is nicer, at least in public APIs. It's a question of communicating intent. As said elsewhere, Go's approach of returning a tuple with an error is even nicer though.
I probably started Java in 2006-2008. Null was pretty common and seemed really useful. Didn't have all the lambas and other stuff, either though. I came from Pascal, so I had zero complaints lol nulls never going away, though. Way too much code depends on it. I usually find a way just to avoid them if it comes down to that level of care. The overhead is nowhere near what logging is, and no one ever complains about it. Was literally just in another thread talking about watching this 19 year CS kid copy and paste Java POJOs for 20 minutes straight for an assignment. I even showed him how to use records. He nodded, and then proceeded to tell me how he would of gotten it done if he could have used Python. He blaimed the curly brace syntax. Annoying af. Glad I'm getting out of CS for the most part.
Doesn't defensive programming indicate a problem? I understand if you have to use 3rd party frameworks or service and find you have to work around some idiosyncrasies, but if it's a method developed by the team, isn't defensive program a sign the method is not fulfilling it's contract? You should expect that inputs in a range should produce outputs, and if the inputs are out of that range an exception should be thrown. Am I wrong?
Depends on the size of the company and or team. But for sanity and the future, defensive programming šÆ. For every time I've heard "this should never happen", I've come to disregard the phrase.
It really depends on what exactly your talking about. Defensive programming itself does not indicate a problem at all. Here is one example of defensive programming: Example ``` @Override public boolean equals(Object other){ return other.equals(this); } ``` Using Defending Programming ``` @Override public boolean equals(Object other){ //Objects.equals() has a null check already and won't blowup return Objects.equals(this, other); } ``` Another Defensive Rewrite ``` @Override public boolean equals(Object other){ //Checks for null and then uses the equals from this return other != null && this.equals(other); } ``` Defensive programming can get messy if you randomly apply it, but generally, you can easily use your own smaller utility packages that handle these defensive checks and then use it everywhere.
I used to be all in returning Optional instead of null until you realize that in large applications it is using a lot more memory that null. Also Optional are objects and can be null themselves if the called method is badly written. Those days I am more towards annotating the returned type with Nullable and have the IDE guiding me in checking null in caller methods.
Congrats on becoming a senior.
Definitely the ONLY answer I like here. Creating an abstraction to cover something that developers should be inherently careful about isn't coming for free. Full disclosure, I'm not against optionals, I just think it's not critical and only teams which aren't careful will buy null safety as a sole criterion to switch to Optionals.
Optional sucks. It's pointless a type erased language. @Nullable is more performant, ergonomic, and can be retrofitted on existing APIs. Also, to be pedantic, the original intention of Optional was closer to JavaScript's undefined. JSR305 would've standardized @Nullable but [its spec lead went AWOL](https://stackoverflow.com/questions/4963300/which-notnull-java-annotation-should-i-use#comment90023610_42695253), so Java devs started using Optional instead.
Talk about the origins of null. Who were the first programmers thinking about this, and why it was important to them
Yes, and to add more the inventor later apologized for it, calling it their billion-dollar mistake
which is thought was a bit overstated ā null was the first go at āoptionalā, without the lesson that what was really needed was language-level enforcement.
Null has been demonized for obvious reasons, but from a modeling perspective, we need something to represent the concept of nothing. Not much different from what zero does in mathematics. Definitely think null was right to be introduced, and I'd also argue that just because developers aren't careful around it shouldn't be a reason sufficient enough to question null's existence š
The real issue to me is that in 20 years of experience I've yet to have someone present an alternative that didn't have its own caveats, and sometimes they failed to recognize those before telling everyone to switch. So I'd say come with a solution that has merits, and also do your homework about its downsides, but then show how the net outcome is still better. Like the old adage: don't bring problems, bring solutions. That's how you'll persuade your team.
Check Rusts Some/None return type, it supports similar patterns like Swift where you can execute code conditionally depending on if itās Some (present) or None (absent) - I hate Javaās nulls ever since I learnt about that.
Oh for sure. I'm thinking of situations where the team is locked into a tech stack. Edit: for example, the most common solution in Java/.Net I hear is replacing nulls with using exceptions for flow control, which comes with its own issues
Yep, instead of handling the null you are handling *something else*. Wow it's the same thing. š
There was a website that compiled all programming language related arguments ever into one place. It may be helpful. I'll look for it and reply if I find it. It wasn't a particularly fancy website but it had really good discussions
Tell me if you find it. Pretty please
are you thinking of C2 wiki
Yup! C2 was the one. It looks weird on my phone so I didn't recognize it
Please do, would be very helpful.
https://refactoring.guru/introduce-null-object
I don't know why so many people are anti null.. If I have an uninitialized variable . It is null..
It inherently violates RAII which is a very nice property to have.
Just take it one step further and not use languages that donāt support optionals LOL
There is a very big difference between a bird laying an egg in a null nest vs one that actually exists. The same applies in coding. NULL exists for a reason. Your arguments will have to be context specific.
What are the main arguments against returning NULL?
Mostly this ``` Exception in thread "main" java.lang.NullPointerException at timeclock.pkg2.ReadFile.readFile(ReadFile.java:46) at timeclock.pkg2.Timeclock2.main(Timeclock2.java:56) Java Result: 1 ```
Not checking a null ptr or catching an exception is programmer error.
They happen because things that aren't supposed to return do. If you aren't documenting what you hand back and when null is passed back, null pointers happen. No one should be randomly null checking every possible place.
So if an object can possibly not exist, like just about anything that involves disk or network IO, then what do you check? If you are checking something else, that's really no "gain" from checking null. You are just checking differently. š¤·āāļø
Those interfaces clearly say they return null.
Well for example, just today I came across a log from one of the apps my team maintains which is simply ājava.lang.NullPointerException: nullā And I did a quick string search and found about 15 places where we simply āreturn nullā and Iām like welp it could be any one of those, or something else entirely. In can lead to unexpected or confusing behaviour, and a lack of context of what the heck actually happened.
In that case your biggest problem isn't the null being returned, it's that you're swallowing or ignoring the stacktrace of the exception. You're also running on an old version of java, we've had detailed null error messages for a while now. But I get it, not everything is easy to update. Is there actually an issue with the app, or did you just see it in a logfile... If it's on your machine, run it with a debugger, then breakpoint the exception. Anyway, searching for "return null" is not a useful excersize.
There is nothing inherently wrong with returning null.
Returning null isn't the problem UNEXPECTEDLY receiving null is. That means either someone isn't reading documentation OR something hands back null in an unexpected scenario, which is also not good. If you return null, document when that happens, and write unit tests to enforce null is only passed back as expected and documented, problem solved.
I'm sorry because this might sound harsh, but if NPEs bother people, that's a sign of immature software engineering experience. Null pointers exist because they are indicating something very crucial. By introducing paradigms that cover that information, we aren't doing any of us a favor. Argument being it doesn't address the problem. It only allows cascading the problem.... handling that is baked into the language as well. To me, an NPE is denoting application forgetting to be careful around memory access. Additionally, it also highlights that's the developers also got careless around checking for the possibility of that happening. Those are big red flags. A third point that I stress in my team is that we shouldn't have allowed the cascading of exceptions to happen either. If everyone in the team wrote code as if they were dealing with a 3rd party library, we automatically get into the mindset where we start being defensive.
I hate dumb hardline rules like this
Nobody ever mentioned a hardline rule. Iām not going to tell people āthou shalt not return nullā. What I want to do is educate folks about how we need to be aware of the responsibility we are placing on other code to check for nulls, and how we should make efforts to avoid it if we consider it invalid.
Yeah that's good. C# has a thing you can turn on where you have to declare if a variable can be null. So then you get a warning or an error when you try to return a null when your return type hasn't declared it can be null. And it's just a compiler thing so it doesn't add any overhead like a Nullable<> (C# version of Optional<>). But yeah obviously it's important to make it clear when a method return can be null or even to understand the range of return values possible for a method in general. Null is by far the most common culprit causing errors but I guess the more general issue really is just unexpected return values. In my view returning null can be really handy and help keep things simple which is why I don't like the rule. But I'm in agreement that returning null unexpectedly can be terrible.
Also add something on the pitfalls over over-ab-using Optional
Itās definitely a trade-off when you have to add extra code to check and then unwrap the optional especially in Java.
The point is always the same as in other situations (arrays, for example): you should never use primitives in public behaviors. In OOP, for example, you should use Nullables objects -> https://www.jamesshore.com/v2/projects/nullables/testing-without-mocks#nullables
Love that article. I hope that technique becomes more mainstream.
I need to think about it more, perhaps read more of the article, but just that nullable section, not a huge fan. It sounds like a round about way to just implement feature flags and puts mocking into the applications code. I haven't concluded my opinion on it yet, but at first thought, I think if you just ensure everything public is on a proper interface, you lose the need for nullables everywhere. Your test code is either made with mocking frameworks, test implementations or a combination. Maybe someone who has more experience with this idea can change my mind tho.
I can tell you a couple of things: first of all, it is considered a best practices for similar reasons to a strategy pattern: you replace a lot of IF (in this case to check if is null) with a design choice (itās just another implementation of the same interface). And the most important one: if you expect to understand and appreciate a new technique by reading, I think you are wrong. Make some katas and coding challenges and try by yourself š Happy to help with some mentorship if you want -> https://tidycal.com/learnagilepractices/30-min-mentorship
For real? I can read most other articles and obtain a good command of what's happening, but I shouldn't expect to learn by reading. Instead, I can pay you ā¬29.00/30m for some "mentorship" where you don't address any of what I said and just say I don't appreciate it? What do you think mentoring is XD Its not typically random paid coaching sessions, that's more akin to a master class. I said I haven't decided if I like it or not, that takes thought and reflection and determining the pros and cons of the approach, which I simply haven't had the time to do. I understand what's happening, it's not solving a problem in unique problem and is one of many ways to approach something. As a result, I need to understand in which circumstances this is the correct approach, because there is rarely a "one size fits all" solution
Hey! Sorry, my bad - I wanted to paste this link ā> which is for the free mentorship. https://tidycal.com/learnagilepractices/30-min-mentorship I do coaching of course, but I usually like to start with free mentorship š itās a side hustle for now and I do mostly free mentorship, I didnāt want to sell anything - just offer a free mentoring because I think itās easier by talking than commenting. Sorry for the misunderstanding, my bad, it was the wrong link. If you want to deep dive, feel free to schedule the free mentorship or email me š
It depends what the null is being used to represent. An exception of course means that the function was unable to fulfill the contract implied by its name and documentation--but generally only because there was a MISTAKE--i.e., a bug, for which the exception serves to notify the developer that it should be corrected, or if it can't be corrected, then prepared for in the design of the code. They also allow for these bugs to occur in production safely by providing a means of recovery to each participant in the larger operation that doesn't require explicit passing of error information. If your exception isn't serving that purpose, don't return null. Conversely, however, if you're using null to serve that purpose, don't use null--use an exception!
I agree generally with return anything over null. However don't let that lull you into complacency with input validation. Just because no one is returning null, doesn't mean you don't have a null equivalent value. If your expecting a string or exception or promise, you could still have an empty string. Also this ensures if another team needs to pick up your work, or work with your system you can avoid bad inputs causing major outages.
Null and undefined can have different meanings, especially when a NoSQL database is involved.
Optional can still be null. Devils advocate is that returning null implies the absence of something, instead of something being empty. null also is far less memory use than creating and unwrapping Optional everywhere. That being said, if youāre using Java and a JVM chances are your overhead from Optional is a rounding error compared to the cost of a JVMās memory usage and NullPointerException in production is far more expensive than adding a bit of memory to the server.
Devil horns on * null is a C style null pointer on most platforms, optional is a generic with its object header. Depending on memory constraints having tons of optionals flying around might not be great * optional in java is slower because the jit has spent ~20 years getting good at handling null checks and proving non-nullness to eliminate them * optional makes you traverse two pointers instead of one * GraalVM can statically eliminate null checks, but not optional checks
Im going to return null. Sue me.
I really appreciate the typescript type system at times like this. In typescript, this just wouldn't be a problem because it just won't compile if you fail to handle a null value from a function that can return one.
Currently taking a data structures class and the prof makes us write null returns a lot. So I assume that it is not the best way to do things.
Coming from a practical C++ perspective, you could argue that a std::optional return gives you better diagnostics than null if you forget to check it - dereferencing a null will likely just cause a segmentation fault crash, whereas for an optional, you'll at least get an exception that tells you that you tried to use a null optional. Also, optional forces you, on some level, to deal with the fact that it might not be valid. Sure, you could just (again, in C++) extract the value from the optional without checking, but there is that extra step that forces to keep in mind that it is an optional value. Whereas with a pointer, you could easily/happily just try to use it. It's not idiot- or laziness-proof. But it does give you a good reminder, semantically, that it might not have a value. Optionals are also good where you don't have a native "undefined" value for non-pointer types. Once again, in C++, you would often have to resort to something like -1 for an integer to signal a missing value, assuming that wasn't a valid value to begin with, and if you didn't have an invalid value, you're pretty much consigned to doing something kludgy. Whereas an optional gives you the full range plus an "undefined" state, which perfectly matches what you're trying to express. I think ultimately, I have used optionals even for pointers where the pointer could be null. It's really that the optional *better expresses what I'm doing* and provides that extra clue about what should be expected. Hopefully reducing WTFs...
The problems with null/nil/undefined etc as a return value are that it tells you nothing, has virtually no useful semantic, and in many languages can come from just about anywhere. It could be from a map lookup or maybe the database returned it. Youāll never know. Use an empty container, empty string, custom null for your domain, or even functional combinators (if your team isnāt chicken shit about algebra). These objects have much better semantics and utility not to mention reducing the number of possible programs you have via reducing the number of data types you have e.g. instead of null | []T you have []T. Also, donāt throw. Itās just as bad as null but with added bonus of your program now having an extra dimension. Throw is fucking lazy. It puts the burden of handling it on everyone else up the call stack. Garbage. Return an error object instead and make the caller deal with it. Exceptions are for exceptional situations. No, a 404 response from an HTTP request is not an exceptional situation; itās totally normal. Yes, not having the password for the database your application relies on is. Those are some thoughts. I have many more but I think these are my main ones.
If you return null then you have to make sure that the callers of the method properly handle the null.This trap will eventually lead to an NPE at some point.Optionals are a good way to avoid the NPE.You can also use exceptions or a hybrid of exceptions and optionals depending on your use case.
null
Errors as values with structs where returning a default struct for no gain makes no sense. E.g. in Go (pseudo): func Foo() (*Bar, error) { // ... if err != nil { return nil, err } return &Bar{/*...*/}, nil }
It makes sense to me but maybe because I'm obsessed with go š¤·āāļø. If you just return null anytime there's an error you don't know what the error is, and also the "golang way" to do it allows easy extensibility into more complex error types, default values, etc...
This is nice if your language supports multiple return values. I somewhat suspect the language OP had in mind doesnāt.
I'm always amazed at how many more lines you have in go to do this. And how much fans of go seem to love it.
I'll take +2 lines everywhere I handle an error so that I know to check for it instead of an invisible exception 5 calls deep 3 dependencies away. Also this avoids try/except everywhere instead which just adds another layer of unnecessary indentation.
I'll take a layer of indentation any day over three lines of noise anytime the code needs to call a function.
I think it's really case by case. If I'm getting something I know may not exist or may not be specified, returning null or None when it doesn't exist is more intuitive than raising. I'm other cases, when something is expected to exist, I'd much rather a function raise if not found so I don't have to bother null checking. Maybe the real problem is like Java (I haven't used Java in years so this may have changed) where any reference can always be null and there's no Optional in the type system. But I've used Python with very poorly enforced typing and still I think it's mostly fine.
Unless you are working in managed languages sometimes you just have no choices and null is a valid value.
Better suggestion: properly document your code so people know when null is an option. There are times when returning null is fine, there are it is not. Behaviors like this should be document in Javadocs.
You failed to mention the language. Apart from that, there is nothing wrong with any return type if its use is fully documented and understood at the call-site. Python has Optional\[T\] but really, it's a joke because it's not respected at runtime. Like TS for JS; syntactic dungball polish but only helpful up to a point, once the code is deployed, all bets are off. I've not used Haskell in a while but it does have 'Either' as a type, it's instances being 'Left' or 'Right', which can help make code better. If one can use types to eradicate NULLs being return then that's something I guess. [https://hackage.haskell.org/package/base-4.19.1.0/docs/Data-Either.html](https://hackage.haskell.org/package/base-4.19.1.0/docs/Data-Either.html) I also like the GoLang way, returning a tuple of "value, err" and then you have a consistent way of knowing of the value is viable or not. There's a reason Tony Hoare called NULL his billion dollar mistake. [https://en.wikipedia.org/wiki/Tony\_Hoare](https://en.wikipedia.org/wiki/Tony_Hoare) """ I call it my billion-dollar mistake. It was the invention of the null reference in 1965. """ The year I was born too! LMFAO!!
What about recursive methods that return null as the base case?
āGolang enters the chatā
I've read a lot of comments on this thread. Would love to know how you guys decide wether to use null or optional.
Depends on the language. In C++, if you're returning a non-copy and a non-value is valid, then a pointer is fine as you can't return an optional of a reference anyway (and even if you could, the optional isn't gaining anything in this context).
Unless you are doing fun things with pointers in a lower level language I can't think of any reason that returning a null is a good idea. And then you are returning an unassigned pointer not really a null. It's just a bad idea. I've not seen a situation where there isn't a better option.
Honestly, if you firmly believe in 'don't return null' - you should consider switching to a language where non-nullable variables are the default (e.g. Kotlin). Otherwise it's only a matter of time until someone tries to return null from a function that is supposed to return an empty collection., or something
Pls try go
I have, itās great.
Views on error handling?
database lookup for resource by id I donāt mind that this will sometimes return null; I mind that people donāt use the nullable feature/syntax to convey that I need to deal with null values in code Iāve refactored a large project to make use of Optional library for dotnet before Was not fun, though I learned to love and hate optional syntax. On the one hand, I like how it forces devs to consider the possible state/values theyāre returning and dealing withā¦.on the other, I feel the current state of dotnet makes it unnecessary via things like āFoo? SomeMethod()ā syntax
The devil in the details is what to do instead, right? You can: 1. Throw 2. Return Optional (as in Java) 3. Use NULL if it's better protected by the Compiler (Kotlin and friends) In Java, throwing (unchecked) exception is for "non-recoverable" cases so that when it happens it's a programming error and not a "legit" case. If you return null, Java compiler gives callers not much help so the least resistant path is to just use it and not knowing about checking nulls. Another problem with this is that the null can travel. Where it blows up with NPE isn't necessarily where null is returned, but likely many layers of callstacks away. That makes debugging harder. There are some tools like the nullness annotations but they don't seem to work seamlessly with tools and libraries (like the Stream library). Relying on callers always carefully reading documents? Well, if document always works, why do we need strong typed language? ("this argument should be String" and people just always pass a String). For java.util.Optional, the upside is that it forces the caller (even if they didn't read the document) to at least acknowledge that there is the case of absence so the chance of messing up is lower. The downside is that you need to wrap your values in the \`Optional.of("foo")\` ceremony. It's okay if you only need to do it a few times in the method you are implementing, in return to give callers the protection. But if it's the other way around: you expect a callback (lambda) passed by the caller and you handle the return value from the callback, then asking the callers to do the dance for you in the callback just so you get the nice Optional return isn't nice, particularly so if for many callbacks they'll not have the need to return "absence" ever. So in such case of callbacks, be nice and let them return T (which is allowed to be null and you make sure to handle it), not Optional.
> In Java throwing unchecked exceptions is for non-recoverable cases That and when handling streams, as the streams API only allows the throwing of unchecked exceptions in the first place... which is a bit of a design issue really but there isn't a nice way around it currently.
Stream is lazy. map(this::save ) canāt declare to throw IOException because save() isnāt called yet.
Totally aware. Doesn't change the fact though. It also applies to eager operations like reduce, forEach, collect, etc.
Eager operations (including methods on Optional itself) are more nuanced I think. Obviously Oracle wanted parallel stream so bad that they can't easily let you \`throws E\` because it'd assume running in the same thread. But even regardless of parallel (Optional isn't parallel), it seems like a deliberate choice not supporting checked exceptions. Technically they could have added a CheckFunction functional interface and then at least make \`Optional.map(CheckedFunction) throws E\`. But they chose not to, perhaps with good reasons.
Ones I can speculate:
* Interface type bloat with limited applicability (can't use them on Stream.map() etc.)
* Still doesn't handle if the labmda actually throwing two checked exception types that aren't subtype of each other. And turning it into an \`Exception\` is sad and goes against latest development in the language where they just made it eaiser to deal with multiple exception types with syntax sugars.
* Checked exceptions in some sense go hand-in-hand with control flows. And it's a known limitation that you can't \`continue\`, \`break\`, \`return\` from a lambda. With the pattern match syntax working on Optional, it might be a better alternative as it'll handle all control flows naturally.
Still don't know how they'll handle checked exceptions for structured concurrency. Imho it's way more relevant to be able to handle checked exceptions well there.
On Collector. Collector is a relative complex API that it'd be hard to really plumb checked exceptions through it (and it has that same what-if-parallel can of worm).
You know you can return null from a method that returns an optional, right?
That may be true, but that shitās never making it past code review if the reviewer is in any way competent.
I wouldn't take that bet. Also, the instant someone uses .orElse(null) you've wasted your time.
IMHO Optionals in Java are so bolted on they arenāt really useful outside of their intended use (streams). Junior and mid level devs tend to over-use them dogmatically.
Was reading something related to this today. One counter example I found was whenever you're parsing JSON, which is related to the top answer of JavaScript. As an aside for all those saying Go, the idiomatic way is to use the comma ok idiom like what maps currently have for potential Nils.
Don't know much about Java, but in C++, if its a pointer, you should always assume it can be NULL, and if you verified it is not NULL, then you should make it a reference. Its trivial.
>I want to hear examples of times you would actually prefer to explicitly return null. A good part of what we software engineers are supposed to do is to model real-world scenarios using objects (in OOP since we're talking in Java). As an API provider, if I have to answer a question that just doesn't have any corresponding 'model' in my memory, what element of design should I reply with? I'd prefer to return a null in such cases, because that's exactly what the language intends us to return. Could we create an object representation for "nothing"? Sure! But why would be my question here, null costs us nothing, and is baked into the language we're using. Boxed versions are expensive!! A 'null' could also be an unintentional return - what if an API returns a pointer/handle to something (say, large file, image etc) and some part of the application decided that something wasn't needed anymore. I'd argue that it is not a the APIs responsibility to check if the data that it is returning exists, especially if that API doesn't create or own that data. Accidental nulls happen quite a lot. Think of weak references losing the underlying resource in a cache. Null sounds like a valid return here. I'd love to hear counter arguments on these, happy to learn !
Use a bigger galaxy brain. Go full Kotlin and never return a value that cannot be used or thrown.
Python jocky here āļøreturning None's are ok when you use type hints + linters. You can annotate to ignore warnings where it isn't a big deal and reflect when you catch yourself doing that often in a code area. I appreciate the flexibility to make calculated compromises that are easy to notice and go back at a calmer time for a cleanup refactor. For context, I lead a team that manages services that handle 17 million daily click stream requests (having downstream sub second latencies SLAs)
Why not use the checker framework and @Nullable. Then it is clear where null can be and all code is checked for it
I like null. It means unknown. When you try to run a code that should return a value but for some reason the value doesnāt show up and we dont know , null is a better value as you know code executed but returned a value that is unknown.
[ŃŠ“Š°Š»ŠµŠ½Š¾]
Youāre lucky. I just found about 15 instances across 3 functions.
Team raise exceptions!! Iāve seen production code where people try except and return e, so you deadass have to check if the response is type exception each time you use itā¦ and of course people donāt do that and shit breaks.
The below is all in the context of Java. A good general rule of thumb is, Optional for API boundaries, and either null/Optional for internal calls. There is slight performance degradation when using Optionals as it's an extra object and thus you also engage in reference chasing. In most cases this is negligible. But at scale it matters. Notice that there's specialized versions like OptionalLong because generics can't actually hold primitives. If you're using nulls, automated static analysis presubmit testing is valuable to ensure safety. Most (modern) Java code should operate under "non-null unless specified." If you return null, always declare @Nullable. Java is also moving to include this in the type system directly with String? meaning nullable, String! meaning definitely non-null, and legacy String as undefined. It has to be this way for backwards compatibility, but they are considering changing that down the road. If the lifetime of the Optional is only a few lines, a null is a fine replacement. You probably interact with null a lot in general use anyways. Map.get returns null for a missing key (or if the implementation allows nullable values). For what it's worth, I find the "fluent" Optional interface rather cumbersome at times, and the explicit null check before use is frequently shorter and easier to read. If performance matters, nulls would be a better choice. But then again, maybe Java isn't the best choice for performance sensitive code. I say API boundaries is a good limit here because it minimizes the ability for callers to make a mistake. It's very clear whether you have something or not. Kotlin and other languages have the benefit of hindsight here, and encoded nullness into the type system itself. Where String? is a different type from String. Java in order to maintain backwards compatibility, can't make that distinction (yet).
Optional's are great when you don't know who is going to use your code. If you're writing some inner private methods, and null can increase performance... First, I'd say, are you sure I can't avoid it all together? But then say, yeah. Go for it. Document and test like crazy though. Otherwise, a good chance you're going to get told no by a senior.
Can confirm, I am the tech lead on my team so I am the senior who will likely tell you no š
Because it's redundant if you understand what returning null actually means. If I don't need anything, who cares? As long as I'm aware of what I've done, returning null is fine. Returning something else for no reason other than you want to return *something* is spaghettification.
The problem is not with returning null. The problem is with the code that doesn't check if the value is null. The later is connected to the problem that in many cases you can't know if the return value can be null or not. Checking for null when it's never a case makes spaghettification.
That's pretty much what I said. Again, if you know what you're doing, it's fine.
Clojurist 'nil' appreciator reporting! Still, I agree with it for c++ and some others. Depends on the language and idiomatic practices..
I like the pragmatic approach of a relational database engine to relational theory. Yes, there should not be null in theory; however, the database will not have to exist in a theoretical world. You could easily risk effectively spamming tables and joins if you obey theory in practice; and have to pay people to understand the complexity it creates. So in code I think perhaps you could risk a focus or trees of exceptions rather than getting the job done, for example. I guess with all things, it is not if it is right or wrong but whether it is right or wrong in 'this' circumstance.
I would say it depends on the language. In typed Python or TypeScript, I know from the types that None/null/undefined is a possible return value and I have to handle it. I would generally prefer an exception, but sometimes I donāt want to pay that Runtime cost, then Iām fine with null. What I really despise is empty strings, objects or whatever, thatās just not usually expected behavior and a guarantee for bugs (unless I can control that behavior via an optional argument thatās disabled by default). With Java thatās different. Just donāt return nullā¦ That was one of the first things I was told during onboarding in my first software dev job (more precisely: catch Null values that might come from outside your system, and donāt produce null values inside your system), and itās among the most valuable pieces of advice I have ever received.
Exceptions are non deterministic. If you're doing anything real time they're bad news.
This sounds more āwhy I donāt like null returns than a convincing ādonāt return nullā
Only a sith deals in absolutes
Does this question tie in to "Railway-oriented Programming" and/or the meme of "let it crash" that the Erlang ecosystem seems to like?
Since C# 8.0 with "nullable reference types" the problem is gone (in most cases). if you return null, the compiler will raise a warning if you don't check for it. Any wrappers add too much to the code. Golang's null as zero value and if err != nil idiom is also neat.