Stop returning null collections in your code

Sdílet
Vložit
  • čas přidán 8. 08. 2022
  • Stop returning null collections and do this instead if you want clean code

Komentáře • 340

  • @Rudxain
    @Rudxain Před rokem +126

    That's exactly what I always do. I learned to think mathematically: If it's valid, but empty, return an empty data structure. If it's invalid, throw an error, because it's a contradiction

    • @davidmata3104
      @davidmata3104 Před rokem +6

      If it's invalid you should return an error not throw errors. Invalid data should be treated as an error (expected behavior)and exceptions should be treated as not expected errors like network failure and so on

    • @Rudxain
      @Rudxain Před 11 měsíci +4

      @@davidmata3104 That's a better approach, and it's what Rust does with its Result wrapper-type

  • @hiTocopter
    @hiTocopter Před rokem +31

    Null-check your lists. You should null-check all variables that you do not explicitly control. There is no reason to handle lists differently. It will lead to inconsistency as opposed to clarity.
    Especially when using libraries that you did not create yourself. Which everyone always does.

  • @gragogflying-anvil3605
    @gragogflying-anvil3605 Před rokem +33

    The additional nesting can also be avoided with an early return.

  • @mrrobot6404
    @mrrobot6404 Před rokem +20

    In c# now they added warning for non nullable reference types.
    So the compiler will warn you if you return null unless you mark the return type as nullable (eg List?)
    And if you do the person who uses that method will get warning that the methode may returns null.
    Cool feature if you ask me.

  • @francp
    @francp Před rokem +106

    If collection should be empty return empty, if it cannot exist throw error, or return null and use nullable/optionals. This tip is too general

    • @jonathansaindon788
      @jonathansaindon788 Před rokem +2

      No its not, there is no benefit to returning a null collection, ever. If you return a null collection to specify that something broke you are doing it wrong. Just encapsulate the collection in an object and set the success or whatever variable to false. Or even better, keep another collection in the return object to include error codes so that the UI can display exactly what went wrong.

    • @francp
      @francp Před rokem +2

      @@jonathansaindon788 Sure, wrapping is "a way" to handle exceptional states, but that's about it, empty collection cannot represent such states, and thats the main motive of this comment

    • @jeffmccloud905
      @jeffmccloud905 Před rokem +7

      @@jonathansaindon788 using boolean return values is an even worse pattern. note that he also said "throw error". and holy shit, returning collection of error codes?? please never try to commit code like that. over engineered and even more "if" checks

    • @temp50
      @temp50 Před rokem +2

      @@jonathansaindon788 " encapsulate the collection in an object" Yeah because a collection is not heavy enough? :/
      I mean you are talking about kind of business objects which was a thing in the past but not really being used nowadays.

  • @davew2040x
    @davew2040x Před rokem +127

    This one just drives me up the wall when I see it. It’s just such a needless way to complicate your code.

    • @dilovarmudinov3600
      @dilovarmudinov3600 Před rokem +2

      Can u elaborate ? Is it bad to return null or is it bad to return empty list ?

    • @jonathansaindon788
      @jonathansaindon788 Před rokem +8

      Returning a null collection is bad. An empty collection does the same thing but is cleaner and no need to null check everywhere in the code. The only reason a collection should be null is if it has not been instantiated yet.

  • @v0xl
    @v0xl Před rokem +25

    rust Option is great

  • @fvlady94
    @fvlady94 Před rokem +13

    While returning null might not be ideal, it's still better than returning an empty collection, because it provides more information to the client consuming your API. Empty array means the operation was successful and the result was an empty array, while null is an exceptional value. Throwing errors or returning failure-specific objects is even better.

    • @TreeLuvBurdpu
      @TreeLuvBurdpu Před rokem +1

      Null would be a half-assed exception. Seems like it would cause more problems than it solves.

    • @vytah
      @vytah Před 7 měsíci

      If only C# had a feature to indicate to the caller when an *exceptional* situation occurs...

  • @robertnull
    @robertnull Před rokem +36

    IMO empty collection is great as a result of some filtrring, but it would be bad as a result of e.g. GetFoodsLikedByUser() - a null would then mean "no data on that", while an empty list would mean "I have data that this user doesn't like anything".
    If the method can return a null, the return type should be List? and then a null ought to be handled everywhere. It's just a matter of choosing where the null makes sense.

    • @tofraley
      @tofraley Před rokem +6

      I have to admit I don't see the difference between "I have no data on that" and "the user doesn't like anything". Those both make sense as an empty collection to me.
      Now, if there was an error condition, then I get it. If that user doesn't exist, it would be misleading to give an empty collection. But personally, I also wouldn't expect to get a null collection either. I would expect an exception or some other kind of error to handle.

    • @robertnull
      @robertnull Před rokem +4

      @@tofraley The difference between "I have no data on that" vs "the user doesn't like anything" is like "we have asked and we have received a(n empty) response" vs "no response received yet, send the poll to the user"

    • @harshmudhar96
      @harshmudhar96 Před rokem +3

      Implicit knowledge == bad.
      Model this explicitly in your code. Write a small wrapper for the query result that describes exactly the business conditions.

    • @alext5497
      @alext5497 Před rokem +5

      @@robertnull if you need data this specific, then use an obj.

    • @TreeLuvBurdpu
      @TreeLuvBurdpu Před rokem +2

      That has to be handled at the data input level. If you have no additional info and the liked foods is empty YOUR SYSTEM is saying they don't like any foods and that's all you system knows. You can't fix that by returning null.

  • @TreeLuvBurdpu
    @TreeLuvBurdpu Před rokem +4

    His example is "a query returned no data from the database". SQL doesn't return null so the null, in that case, would obscure information.

  • @Xevion
    @Xevion Před rokem +4

    If the behavior of the code requires different functionality when the collection has 0 elements, then you haven't simplified anything, only made it slower.

    • @kotokotfgcscrub
      @kotokotfgcscrub Před rokem +1

      null check is way faster than creation of collection, especially if memory allocation happens during it.

    • @vytah
      @vytah Před 7 měsíci

      If the behaviour of the code requires different functionality depending on some conditions, then use an appropriate return type that encodes those conditions.

  • @AdamGaffney96
    @AdamGaffney96 Před rokem +23

    I agree mostly, but there are some situations where an empty collection is not the same as a non-return.

    • @jonathansaindon788
      @jonathansaindon788 Před rokem +1

      Can you give an example? I highly doubt that there is no better way to do what you think.

    • @klocugh12
      @klocugh12 Před rokem +2

      @@jonathansaindon788 e.g., you use external API that actually expects null collection.

  • @otesunki
    @otesunki Před rokem +12

    as a rustboi, i am required to mention Option

    • @maxclifford937
      @maxclifford937 Před rokem

      Honestly, if you are just iterating over it I'd tend to return an empty collection still (in both F# and rust) unless there is something specifically different between no results and one or more results. Only because it cuts out an extra check for the consumer.
      Also I'd possibly be tempted to replace option with result if there is a specific difference, because that way you can add extra information if it is empty.
      But it depends on the situation (though I have found in 99% of cases an empty collection and an optional collection that is none if empty are basically the same thing)

  • @EmmaKAlexandra
    @EmmaKAlexandra Před rokem +37

    Just use an optional type. If you’re trying to get rid of the nesting, use a guard statement instead

    • @Schnorzel1337
      @Schnorzel1337 Před rokem +4

      While Optionals are great, if the codebase is well maintained, an empty collection is prefered. You know you got no results so why make it uncertain if you got something or not?
      Optionals are better than null tho.

    • @asdqwe4427
      @asdqwe4427 Před rokem +1

      @@Schnorzel1337 agreed. Optionales are better when you try to find one of something.

    • @Sk4lli
      @Sk4lli Před rokem +3

      @@Schnorzel1337 There's a difference, if the Collection being empty is a valid result then returning an empty collection on an error might not always be the best option. It depends on context though.
      But I prefer in error cases to get null and an error. If the result is null, I immediately know something went wrong.
      Working with code where something like 0 is returned as valid value and error can be so much pain.

  • @daveevad3524
    @daveevad3524 Před rokem +9

    As someone who uses other people function, the BEST practice is also to always check for null because I'm not sure if THAT coder watched this video!
    So while it is a GOOD practice for the function coder, It is a BAD practice for the function consumer to assume that the function doesn't return null.

    • @vytah
      @vytah Před 7 měsíci +1

      There is no reason why this function should return null. So you can either assume that the author wasn't braindead and the function doesn't return null, or dive into the source code only to discover with 99% probability that the function indeed does not return null and you could have just assumed it in the first place and saved time.

  • @MartinStephenson1
    @MartinStephenson1 Před rokem +3

    Good practice. Resharper will still complain that the collection may be null when you use it and insist you add a null check to shush it up.

  • @iSoldat
    @iSoldat Před rokem +45

    Yeah, this is what I'm used to doing. Unfortunately, my tech lead has made returning nulls his personal preference. Fortunately, I'm awaiting a formal offer from another company and will be leaving his unwillingness to listen and his bad coding practices soon.

    • @xybersurfer
      @xybersurfer Před rokem +6

      i can totally relate to how much it sucks, when people that are supposed to be reliable won't listen to reason

    • @iSoldat
      @iSoldat Před rokem +6

      @@xybersurfer It's all good, I'm packing my bags and moving to greener pastures. Accepted a verbal offer yesterday.

    • @astrahcat1212
      @astrahcat1212 Před 7 měsíci +1

      Tech lead? Is he older?

    • @dsuess
      @dsuess Před 6 měsíci +1

      @@astrahcat1212 Same scenerio here. Years back, my previous "lead" was was the same age with must-less experience. He just threw tantrums louder than everyone else. *smh*

  • @adichowdhuri
    @adichowdhuri Před rokem +4

    Simple code >>> less code

  • @JesusReinaC
    @JesusReinaC Před rokem +3

    Even if this is a common convention, it is always a good practice (defensive) to null-check!))

  • @markusmulholland
    @markusmulholland Před rokem +1

    So what if it's an issue that no data was returned? You can't just iterate over an empty collection and skip essential logic. The point is that you want to iterate over data that you expect to be there so you have to check for an empty collection anyway. You would rather want an exception thrown in that case indicating malformed data rather than essential logic just being missed. To negate that, you have to check for an empty collection in the calling code. You are now instantiating a type just to return it and check if it is empty. Null was built for exactly this.

    • @markusmulholland
      @markusmulholland Před rokem

      I suppose this is in the case that you require data to be returned eg: getting the products in an order that a customer has paid for. In the case that you are iterating over orders to display on a dashboard, I can agree with your pattern. It is most certainly not a catch-all pattern though.

  • @davidbares8482
    @davidbares8482 Před rokem +5

    The problem is that now the function caller assumes that it always has good data being returned and doesn't bother to check for nulls anymore. And then maybe the code is copied or reused somewhere else where the function is changed to one that does return null.
    I always check even if it's not possible, just in case. One legacy system we have recently had one old bug pop out of nowhere because it didn't check for nulls but recent changes in the data (not code) now made it possible.
    When collaborating with other coders, you want to assume they messed up and always have checks in place (or perhaps catch exceptions and take care of them).

  • @jackkendall6420
    @jackkendall6420 Před rokem +10

    I'm very happy to see Nick using Linux memes in his videos

  • @dimalisovyk5277
    @dimalisovyk5277 Před rokem +2

    I wish they added non-nullable references from 1.0 like in Kotlin. It would make our life easier.

  • @alex_jellymath
    @alex_jellymath Před rokem +5

    In short: author's opinion is weird, read the doc for your language for actual better way to solve this issue. That might include continuing using null (see: Kotlin, maybe new Dart/C# projects, Typescript), throwing exceptions (see: Java), using Option/Maybe/Optional type (see: Java, Scala), using sum types (see: new-ish Java, Scala), using some default value (kinda like in the video) and probably many others. Your language of choice probably have multiple of those things for the different types of situations. Sometimes you will combine multiple of them.
    Longer:
    The video highlights two issues with null for collections: unnecessary nesting and potential issue of accidentally forgetting to deal with null. As the result video suggest to use empty collection instead. It's also done generally without considering the language (but demonstrating C#)
    First of all, I don't really see how null is different for collections comparing to other things: it is kinda annoying if your int or string is null the same way as if your collection is null.
    Unnecessary nesting is might be an issue for C# but not necessary for all languages: Kotlin, Dart, Typescript and probably many others can deal with null value with single LOC if needed because of flow analysis. For some other languages it might be a design choice: yes, you have more nested code, but you ensured that all possible problems are processed accordingly.
    Accidentally forgetting to deal with null is also the one that really language dependent. Not really an issue for Kotlin, new-ish C#, new-ish Dart, Scala 3, Typescript and many others (in some cases, config for null safety needs to be enabled). Languages that have null and decided not to solve null safety problem are mostly migrated to Option types (Java, Scala 2, etc) so using null is kinda bad in this case but for the other reason.
    Having empty collection or some default result in general instead of null is fine in some cases when it's known in advance that processing "unhappy path" doesn't really makes sense but not always: sometimes you want to give function caller a choice to deal with this bad condition. And if this bad condition is pretty simple then it might be fine to represent this result as null if that's a norm for your language (it is for Kotlin, see: toIntOrNull). Same goes for Option types. If the condition is not that simple or it's generally better to always avoid nulls in your language, there are always exceptions and sum types.
    So overall the advice might be helpful for C# development (I am not that familiar with it, so cannot say for sure), but it doesn't really that helpful for programming in general as languages and their practices evolve in a very different way.

    • @Schnorzel1337
      @Schnorzel1337 Před rokem +1

      There is absolutely no reason to ever return null.
      You return null to indicate an error, but you cant tell the developer or the compiler what kind of error is to be expected. Also you are not enforced to handle nulls, which is obviously bad.

    • @alex_jellymath
      @alex_jellymath Před rokem

      @@Schnorzel1337 Again, not every language is the same. Java will mostly not force you to handle null, but Kotlin will. Even new-ish C#, Dart and Scala will if the project is configured to do so.
      About the lack of expressiveness - that's true but also sometimes that doesn't matter. I mentioned toIntOrNull before - while in theory you can have more than one problem with the input (it's not a number, it's too big for Int type), usually that doesn't matter so you are fine with "you either get an Int number or you get null and you know that the input was invalid". Same for Option type - despite having more expressive options (like sum types and Either), many languages still include Option (or Maybe, Optional, etc) as sometimes you are fine with simpler type.

  • @LCTesla
    @LCTesla Před rokem +13

    Returning empty collection is a way of pretending everything is fine. Oftentimes it's better to throw an exception. I would argue you actually want to force your consumer to code defensively against real disruptive edge cases. The nullpointer exception is of course still the worst way to communicate this.

    • @11clocky
      @11clocky Před rokem +12

      It isn’t pretending that everything is fine. Everything IS fine. It just means that there is no data to find in whatever the method is querying.
      If an actual error occurs in the method, then yes an exception should be thrown. Finding no data? Then no, there is no error, just no data.

    • @LCTesla
      @LCTesla Před rokem +6

      @@11clocky "someBadCondition" doesn't mean everything is fine. He's talking about exceptions which should be handled as such. Empty collection is for when the happy flow finds nothing, as you said, but that is not what this is about. You shouldn't need to present an empty collection if your happy flow already does it.

    • @LCTesla
      @LCTesla Před rokem +1

      Another good way to handle this is to force the consumer to exhaustively match the pattern of your return type - define the possibility of abberant results as a form of your return type and enforce that the case is handled. But thats not possible in every language. F# and Rust can do it. I forgot whether the latest C# versions can.
      In fact that's how Options work generally in F#: like nulls but ones that your compiler warns you about when you don't match them.

    • @LCTesla
      @LCTesla Před rokem +2

      @@MiningForPies so you're agreeing you should throw exceptions when it's exceptional.
      Thanks.
      as for when an error is unrecoverable, that is up to the consumer. Not my call to make.

    • @LCTesla
      @LCTesla Před rokem +1

      @@MiningForPies your responsibility towards the consumer is to communicate, not hide problems.
      If the consumer wants to just continue unhindered he can just wrap your call in a method returning empty collection.
      Not your call to do it for him/her.

  • @EpsteinDidntKillHimself
    @EpsteinDidntKillHimself Před rokem +3

    and what you might receive instead is an infuriating process of figuring out why the collection you're getting back is empty

    • @Schnorzel1337
      @Schnorzel1337 Před rokem +2

      NullPointer thrown at Line xx. Is that better?
      But you are right, throw exceptions if there was a bad case.

    • @xybersurfer
      @xybersurfer Před rokem +1

      usually you have to loop through a collection you receive, so it being empty is not a problem. the code is just done looping immediately with an empty collection. so you can usually use the same code to deal with any collection, empty or not. this is the payoff. but when you introduce null, then you force the caller to always make a distinction and they will probably forget sometimes, after getting tired of writing the same distinction that they don't need.
      but the problem you are actually talking about is receiving an unexpected value. just like you can receive the empty collection unexpectedly, you can also receive null unexpectedly. receiving an unexpected value is what's frustrating. and changing that value to null does not make it expected, so that really doesn't solve the problem.

  • @mo_mo1995
    @mo_mo1995 Před rokem

    That's why null coalescing is a must-have programming language feature. Just add "?? []", or whatever the language syntax is, after the nullable collection. If the producer think returning null makes sense, they can do it. If the consumer doesn't bother dealing with null, they can do it too. Everyone happy.

  • @jongeduard
    @jongeduard Před rokem +3

    I get the point, but I do not come to the same conclusion: Most important is that you are aware of these implications of returning null when it comes to collections/arrays.
    But this does not by definition mean that I never return null. To me, returning null simply means something totally different than returning an empty collection!
    Imagine any situation with dynamically created database tables or files filled with a set of data. Imagine a method that reads these and returns the data from it.
    In such situations, it can be critically important to make difference between when the source file or table does not exist (in case which you really want to return null) and when it's just empty (so you will return an empty collection likewise)!
    In other cases, returning null can mean that something went wrong. Alright, in many of those cases, you can say: throw an exception instead, but I also know certain cases where this does not hold.
    In the end: the most important thing is just knowing about how your code is being used, and making your intentions clear. Nothing more.

  • @jonasbarka
    @jonasbarka Před rokem

    The initial example is a bit weird, as the return type is List, which doesn't have an Empty property or method.

    • @shadowpony9243
      @shadowpony9243 Před rokem

      works with generics to

    • @jonasbarka
      @jonasbarka Před rokem

      @@shadowpony9243Many generics, but neither List nor List.

    • @nickchapsas
      @nickchapsas  Před rokem +5

      You can return IList which accepts the Enumerable or simply return new List. Yes it allocates memory. No you you don’t have to worry about it.

  • @user-qz6ix7od3b
    @user-qz6ix7od3b Před rokem +1

    thanks. will always do that. but there will still be one grinch out there who will not. so i still have to write a null check every freakin' time 😆

  • @amichelis
    @amichelis Před rokem

    It depends. If you want to indicate an error (ie a filter user applied is not valid, not just a query that yielded no results) null returns can be usefull, if you don't want to encapsulate your whole returning data to a separate structure that also needs success-checking. headache-causing? yes. helps developers to learn better handling results? also yes.
    Additionally, NOT having an exception thrown in such case, can lead to WAY more headaches, as logic errors tend to do
    Also, optionality is another case of null usage. If a class can *optionally* have a list within it, null can provide the same functionality as an extra boolean field, with double space saving (no initialized list and no extra field).

  • @hentaxxx
    @hentaxxx Před rokem

    probably another way to explain this Array.Empty() doesnt make allocation and this pretty good for your performance :)

  • @BushiestBesver
    @BushiestBesver Před rokem

    Wow so simple. 4 year in industry first time seeing this thanks

  • @parlor3115
    @parlor3115 Před 2 měsíci

    Probably meant return an empty set as a default if the parameters are projected to yield no results or so, because there's no point checking if the database result set is empty.

  • @fvbixn
    @fvbixn Před rokem +1

    Hm, I find it useful when using typescript, because I can determine if there is data, but the length of the array is 0, or because there was something wrong with the data loading/function execution and it is returning null. You can use it for error states, when building UIs. An empty array would be an empty state (you don’t have any xxx), a null return would be either (there was an error loading) or something. But of course it’s not the only way to do it.

    • @vytah
      @vytah Před 7 měsíci

      Typescript encodes nulls/undefineds in the type system, so the caller is not going to be surprised by them, so the video does not apply to it.

  • @nomadshiba
    @nomadshiba Před rokem

    when people return null on a list or array its so it gives an exception and not gets skipped by the foreach and stuff like its a zero length list, which is not
    there is a difference between array is being empty and doesnt exist at all

  • @trumpetpunk42
    @trumpetpunk42 Před rokem +1

    Ah, null -the "trillion-dollar mistake" that Java made, and then c sharp just copied its homework...

    • @peryvindhavelsrud590
      @peryvindhavelsrud590 Před 11 měsíci

      Well, Java doesn't have struct types, which actually are guaranteed to have a value except for the Nullable type that overrides the behaviour because something being null in a lot of cases actually is different from it having a default value. Especially if you deal with numbers, I've seen too many instances of magic numbers breaking computer systems because someone decided "that value is far enough from the normal uses for this value. That sure wouldn't be valid in any situation". And boom, customer needs the magic value to have it's actual value instead of the decided upon meaning. I've seen -1 being used as not set when dealing with strictly positive values, but if all values in an integer range are allowed, that's no longer possible, and why allow negative values at all if you could use a unsigned value instead, which actually convey information that the value is guaranteed to be positive or non existent as well. And you don't need to handle situations where it was suddenly -128 because of someone using it wrong and thinking int mean int

  • @TheRealLyonic
    @TheRealLyonic Před rokem +3

    If we're worried about someone using the codebase that doesn't know the collection can be null causing an error by trying to use the values in that collection, then we're going to run into the same problem if we return a collection with blank values, except now it's going to be undetectable because it won't throw an error. Say they write code to iterate over the values, and don't add a check because they don't know it can be an empty collection, there's then gonna be a bug in their code that they won't even realize is there because it never throws an exception, even when it's broken. And even if they manage to see the broken functionality they're still not going to know how to fix it, since there wouldn't be an error message explaining that the issue is that the collection can be null--or in this case, empty. It would just be a hidden problem that someone would have to sift through the entire codebase to find because a proper iterable collection type was returned, instead of a null value, which would have told the developers where the problem was and what was causing it.

  • @prophtube
    @prophtube Před 7 měsíci

    Great tip. Makes it better for everyone!

  • @alimorgan1407
    @alimorgan1407 Před rokem

    I have a question, why is it than when I try to return Enumerable.Empty(), it won't compile becuase the collection, (which in my case is a List) can't be implicitly casted, and when I convert them explicitly it throws an invalid cast exception! Therefore, I have to return null, or manually generate a new empty collection.

  • @SXsoft99
    @SXsoft99 Před rokem

    Basically have one return type for the method when you have a list/collection/array, well unless it's a map-array/obj then you can return null

  • @leandroteles7857
    @leandroteles7857 Před 5 měsíci

    Am I the only who tries as hard as possible to keep IFs as one-liners everywhere, so that you can omit the braces?

  • @seifeldinismail5005
    @seifeldinismail5005 Před rokem +2

    Guard clauses exist

  • @dontBeAParrot
    @dontBeAParrot Před rokem

    What about non-collections/ other nullable types, like strings? Can this advice translate to that? Could returning an empty string be better than returning a null, wouldn't a check be required in the client code anyways?

  • @eslof
    @eslof Před rokem +4

    this is all wrong. use the questionmark to create a nullable type so you can return null.
    use EARLY EXIT to avoid extra indentation eg:
    if (!condition) return null;
    your code here...
    instead of
    if (condition) {
    your code here...
    }

  • @yunsha9986
    @yunsha9986 Před rokem +1

    Wouldn't you be writing a condition to check for empty collection anyways. Most of the time, your code doesn't simply end with the for loop, there's probably another logic that is triggered just after or something.
    So my question is, doesn't it like save a huge amount of time writing a condition for empty collection and ending your function? Then, if YES, what did your solution actually solve, the guy who wrote return null, was putting a condition check anyways.

  • @TreeLuvBurdpu
    @TreeLuvBurdpu Před rokem

    I didn't even realize returning null for a typed function was something people might do. Isn't there a way to lock out that option in a code setting? I can't remember seeing that in any reviewed code, but now I want to lock it out.

  • @temp50
    @temp50 Před rokem +1

    Meh, then how you differenciate between "legally" empty lists from "illegally empty" ones?
    For example if the query not expects to have an empty resultset from the db, but wants to tolerate this case (so doesn't want to throw an exception) how would you indicate a potentially "warning level problem" to the caller code that something was not right?
    E.g.: The db has probably been compromised or was meant to be uitilized by an other version of the sw so it's not compatible with the current code, etc...

    • @vytah
      @vytah Před 7 měsíci

      You mean some kind of an exceptional situation? I wonder if C# has a feature to indicate an event that one would call an exception...

  • @electricengine8407
    @electricengine8407 Před rokem +2

    who would even do this in the first place

  • @fabianramirez3222
    @fabianramirez3222 Před rokem

    Well... It goes to a fundamental question about if a null value is actually a collection/array. That what needs to be validated with a conditional everytime if devs choose to say "yes".
    In my opinion, null should be avoided as value for arrays as much as possible, as evaluating empty array makes much more sense and is less ambiguous that evaluating a nullable value. For example, in JS, a property with empty array as value for sure is an array, while the same but with null vale can be anything.

  • @thomasschroter3802
    @thomasschroter3802 Před rokem

    Well.... no! You just shift the null check code to the creating function and have to repeat it everywhere. A much better and yet pragmatic solution would be an extension for IEnumerable , e.g. :
    public static IEnumerable valid (this IEnumerable list)
    => list?? Enumerable.Empty ();
    that enables you to write
    foreach (var item in list.valid() ) ...
    but there is even an better way to do this, by using a null tolerant general each() extension as part of a fluent API / DSL. Feel free to contact me about details.

  • @dominicc1804
    @dominicc1804 Před rokem +2

    Definitely eliminate nulls with extreme prejudice! Of course sometimes it isn't doable without bending over backwards, but those should be the very rare exceptions to the rule. The only place you should need to check for nulls is at points where data is entering the application, eg endpoints, file reads, queue consumers and DB reads.
    Regarding the database example, if querying for something that should be there when the application is behaving normally, I prefer to throw an exception when it's not there. The main cases when I return an empty collection are either search results or optional child collections. But in general I like to pin down the rules and be very strict about behaviour because that leads to certainty/strong confidence and relatively low and painless maintenance.

    • @xybersurfer
      @xybersurfer Před rokem +1

      exactly! i'm also super strict with the number of expected result. i learned how useful this is from LINQ functions like "Single". it's usually best to catch problems early

    • @dominicc1804
      @dominicc1804 Před rokem +1

      @@MiningForPies yes I consider anything contrary to the normal state and behaviour of my applications to be exceptional.
      In the most extreme case, I'd rather my application dies in mission critical production due to an uncaught exception than to behave in undefined ways that could mess up the DB or execute undesirable actions.

    • @xybersurfer
      @xybersurfer Před rokem +1

      @@MiningForPies to me: whether it is exceptional that no data is being returned from a function, depends on all the ways that the function can be used:
      - if it's invalid, then there should be an exception.
      - if it's sometimes valid for it to happen, then i don't make that function throw an exception and instead have the caller validate the result and throw the exception. of course i create a specialized function, when multiple callers have to do the same validation of the result.
      i'm not sure what you mean with exceptions instead of "proper control flow and logic". but there can be situations where exceptions are awkward. like when you want to validate all user input and not throw an exception at the first sign of invalid input. common sense helps here.
      but i'm with Dominic C in that by default, i would rather have the whole process end as quickly as possible at the first sign of trouble and have a rollback and report the error or whatever, instead of having it keep on grinding and do who knows what kind of damage (i've seen it happen). having it keep going honestly sounds like no plan at all. i believe that like many things, the later you catch the problem the worse off you are.
      also when you use control flow instead of exceptions, you are basically reimplementing the exception handling mechanism and cluttering your code with it instead of the business logic. not using exceptions typically causes you to create things the Arrow Anti-pattern, and at the very least greatly increases the possibility of forgetting to manually check for error conditions (and you will forget it at some point. i've seen it many times). exceptions for invalid data is the default, even by the .NET Framework. usually there is no reason to fight exceptions. it's not a matter of being lazy. it's a matter of being consistent

    • @dominicc1804
      @dominicc1804 Před rokem +1

      @@MiningForPies if you're not strict about behaviour and state, and your app is full of if's, but's and maybe's, the cyclomatic complexity grows exponentially until you have a big ball of mud (technical term 😉) and it reaches a point where any modification is too much effort (aka too expensive) and it needs to be rewritten. I'm referring to enterprise apps under long-term active development of course.

  • @pepenaman
    @pepenaman Před rokem

    I often try to avoid null returns, I rather return a standard "failed" value, such as "-1" for integers, or an empty String so I prevent getting into troubles with what even is the "null" value is in the language I'm working with, and if I end up needing nesting anyways at least I have a value to work with and it's still readable.

    • @Schnorzel1337
      @Schnorzel1337 Před rokem +2

      Please consider using optionals or even exceptions instead of returning -1.
      If your method returns an index of -1, that might lead to an access on a datastructure, which will end up as an OutOfBoundsException.

  • @mordechaisanders7033
    @mordechaisanders7033 Před rokem

    C# 13: we introduced a null-coalescing range based for

  • @dohnud
    @dohnud Před rokem +3

    So instead of a null checks all over the place there are empty checks all over the place! Problem solved!

    • @nickchapsas
      @nickchapsas  Před rokem

      When you write a for loop or use linq on a collection, do you have an empty check? Ofc not :)

    • @dohnud
      @dohnud Před rokem +3

      @@nickchapsas yeah when doing something functional. I’ve been plagued by the flip side of the null problem where I get back an empty list when an error code should’ve been thrown (js)

  • @Garneg
    @Garneg Před rokem

    Goddamn, i so love kotlin for warning me if method can return null

  • @jangohemmes352
    @jangohemmes352 Před rokem +8

    Be very careful with null. I'm very happy C# has the ability to get rid of nulls

  • @dabbopabblo
    @dabbopabblo Před rokem

    True think of it like the developers of MySQL for node did, if there are no results return the array with… you guessed it, no results

  • @adrianczupak4271
    @adrianczupak4271 Před rokem

    I always try to think that person who calls my function will never look into it.
    So the function declaration is a contract.
    If returned type is nullable it means that function could return null. So in my opinion better practice is to do a null check and handle it if we know what to do in that case. If not then let the NullReferenceException be thrown.

    • @nickchapsas
      @nickchapsas  Před rokem

      And what do you do when your method returns a validation exception when validation fails? How will the consumer know without looking into it?

  • @DVSProductions
    @DVSProductions Před rokem +1

    I'm confused why nobody is mentioning yield return here. This would be a perfect situation for it, especially since you are already using IEnumerable as a return value. If there is an error just don't return anything and your function will automatically return an empty enumerable, fully automatic and nobody has to worry about null issues. And if someone wants to convert it to a list they can just use .ToList()

  • @gwentarinokripperinolkjdsf683

    This is terrible too! now something has gone wrong, and the programmer was not informed via an exception.

    • @vytah
      @vytah Před 7 měsíci

      Then throw an exception instead of returning null.

  • @StarfoxHUN
    @StarfoxHUN Před rokem

    Just to avoid any unwanted behaviour, i think a nullcheck wont hurt, even if you sure it currently wont return null, as noone can be sure about the future of the used method. One day one guy modify it and then the fun begins...

  • @futuro4497
    @futuro4497 Před rokem

    you could use the optional type if you want to return something else than a collection

  • @typhoonf6
    @typhoonf6 Před rokem +2

    What's the difference between checking for null and checking for an empty collection?

    • @Sk4lli
      @Sk4lli Před rokem +1

      An empty collection might be a valid response, null explicitly tells you something went wrong. ;-)

    • @typhoonf6
      @typhoonf6 Před rokem +2

      @@Sk4lli isn't that what exceptions are for? I would argue a null return doesn't "explicitly" tell you anything.

    • @Sk4lli
      @Sk4lli Před rokem

      @@typhoonf6 Of course null itself doesn't contain any data of what went wrong. If that is needed, then I'd return an error object. I only use exceptions for handling unexpected errors that can't be checked with regular logic. Since exceptions have a huge performance impact.

    • @vytah
      @vytah Před 7 měsíci

      Why would you check for an empty collection anywhere except for UI code (where you would want to display "(no data)" instead of nothing)?

    • @typhoonf6
      @typhoonf6 Před 7 měsíci

      @@vytah dunno, why would ya

  • @petrushoc
    @petrushoc Před rokem +5

    Use Either monad 😂

  • @asherrfacee
    @asherrfacee Před 8 měsíci

    Very good tip thank you.

  • @StopBuggingMeGoogleIHateYou

    Bad advice. There is performance overhead involved with creating objects that you're not going to use: memory, processing, and cache. This is how you make your code slow.

    • @nickchapsas
      @nickchapsas  Před rokem

      Not there isn’t. .NET won’t allocate for empty arrays for example if you use Enumerable.Empty or Array.Empty

    • @StopBuggingMeGoogleIHateYou
      @StopBuggingMeGoogleIHateYou Před rokem +1

      @@nickchapsas That may be true for .NET and the containers you mentioned, but it's not true for every container and every language. For example, in C++ (when compiling with Visual Studio), allocating any STL container other than string or vector will immediately allocate memory. You need to be thinking about these things when applying advice like what's in your video. However, I will grant you that the "shorts" format doesn't leave time for a lot of nuance.

  • @spicywasab
    @spicywasab Před rokem

    In js we have the optionnal chaining operator ?. to be able to chain methods without throwing an error if one returns null or undefined.
    like :
    getUsers()
    ?.map(anything)
    .reduce(something);
    if getUsers returns null or undefined instead of an array, ?.map will return undefined and no more method will be executed.
    However I still agree, returning an mpty array if there's no data is better than returnint null.

  • @j1shin
    @j1shin Před 7 měsíci

    One of the bad practice advices I just cannot agree on. Safety and robustness before having less code.

  • @astrahcat1212
    @astrahcat1212 Před 7 měsíci

    Why are exceptions being thrown bad again? You wanna see those errors.

  • @kinggrizzly13
    @kinggrizzly13 Před rokem +2

    Wonderful tip! I’m sending this link to my team. Thank you.

  • @dilmerv
    @dilmerv Před rokem

    Great feedback !

  • @jasonfreeman8022
    @jasonfreeman8022 Před rokem +9

    😂😂😂 - “I use Arch by the way!”

  • @tedcyted9994
    @tedcyted9994 Před rokem

    I thought that if the data set is null, foreach doesn't goes inside the loop block. ???

  • @MrRobin4444
    @MrRobin4444 Před rokem

    just return default everywhere is the best solution, i promise.

  • @ShiNijuuAKL
    @ShiNijuuAKL Před rokem +2

    You never know what bullshit the previous developer did so you basically always need to check. And if you don't check and another developer changes the code so that it returns null, then you will have a bug. There's no easy solution for this apart from changing to a better programming language that doesn't use null values like Elm.

    • @ce9474
      @ce9474 Před rokem

      But in C#, if you're working in a nullable aware context, that list cannot be null unless it's made a nullable. You can treat nullable warnings as errors and you'll never run into those sort of bugs (given that all code is nullable aware).

  • @GBSCronoo
    @GBSCronoo Před rokem

    Did not know you could do that cool!

  • @grandeau3802
    @grandeau3802 Před rokem +1

    What about other types / non-collections? Strings for instance. Would you avoid null in any case and always use string.Empty?

    • @asedtf
      @asedtf Před rokem +1

      Null is not a concept to avoid.
      If you try to get something by key, and there's no item for that key, you should handle that by exception.
      If the value for that key is indeed null, that's a valid result.
      You can use the TryGetValue pattern to explicitly inform the result and avoid exceptions

    • @xybersurfer
      @xybersurfer Před rokem +1

      avoid null when you don't need it, but not at the cost introducing magic values. null simply means no value. the language designers messed up by always allowing some types like String to be null, when it actually depends on the situation

    • @asedtf
      @asedtf Před rokem

      @@xybersurfer every language that doesn't have null as a concept either has an equivalent way to define a non-value return.
      Heck, JS has two null values!

    • @xybersurfer
      @xybersurfer Před rokem +1

      @@asedtf i'm not sure what you mean with "either". i can't tell if there was supposed to be a comma after it, or whether it means "either or" and you forgot the "or" somewhere.
      i'm guessing you are referring to undefined and null in JS. i think that was a terrible decision. now you have to wonder which to check for. 1 of them would have done the job. it's one of many problems in JS. at least the JSON specification has the good sense to only have null.
      it reminds me of VB6/VBA, where there is Null, Default, Empty, Missing, Nothing. it just creates confusion

    • @grandeau3802
      @grandeau3802 Před rokem +1

      I agree with both of you. Had a conversation once with someone who insisted that null is a no-no and has to be avoided at all costs. But there is a difference between a empty and a non-existent string, like 0 is not equivalent to NAN. I rather have an exception then a strange behavior of the program where the root of the cause is hard to find.
      BUT: doesn’t that apply to collections as well?

  • @Poke52380
    @Poke52380 Před rokem

    For enumerables this is fine, but you should never return an empty List instead of null. You are allocating a useless value just for some convenience. If you are not familiar with the internals of the function you are calling, null should still be checked for. The real problem here is not returning null, but that most collections are a reference type instead of a value type. This solution is just patching over a crappy language/runtime.

  • @MrUdens
    @MrUdens Před rokem

    But then it means that your method should retrieve IEnumerable instead of List.

    • @nickchapsas
      @nickchapsas  Před rokem +1

      If you need to return List then return new List.

    • @MrUdens
      @MrUdens Před rokem

      Totally agree! But after viewing your short about GC and List allocation - I want to return new List less often😁

  • @7th_CAV_Trooper
    @7th_CAV_Trooper Před rokem

    I love the shit emote for returning null. I want to use this emote in code reviews.

  • @shahfaisal3923
    @shahfaisal3923 Před rokem

    you are my mentor.

  • @semen-sage
    @semen-sage Před měsícem

    In fact when EF Core’s ToListAsync also returns an empty list if there’s no data found. 100% agree that you should think twice before returning null, especially when dealing with something IEnumerable. And Enumerable.Empty allocates just once for a given type, no matter how many times you return it.

  • @tplummer217
    @tplummer217 Před rokem +1

    Awesome

  • @malakggh
    @malakggh Před rokem +1

    Throw an exception instead

  • @MsbowElite
    @MsbowElite Před rokem

    Is there any way to override List and make impossible to make it null?

    • @peryvindhavelsrud590
      @peryvindhavelsrud590 Před 11 měsíci +1

      @MsbowElite No, since List is a reference type, it is heap allocated and therefore allowed to be instantiated. There are collection types that can't be null, but they are a bit of a hassle to work with for multiple reasons (scoping being one of them) Don't know for sure, but check if this channel has videos on Memory or Span, Wich are the simplest to work with if that's something you want. Fair warning though, they are a bit more hassle to work with, and are more like arrays than lists in how they work. I tend to return IEnumerable and implement by using yield return and yield break instead, as you, using the proper implementation can guarantee that the results are always not null. I do however sometimes return null lists as well, but that is often to communicate that the list itself does not exist, when there is a distinction between the list not existing and being empty.

  • @explodatedfaces
    @explodatedfaces Před rokem

    But thats why you would create a single class for obtaining the object as the consumer... so you only if to write (x is not null) once...

    • @Schnorzel1337
      @Schnorzel1337 Před rokem +1

      Bad practice, you will only confuse people by wrapping your return collection into a different class.

    • @explodatedfaces
      @explodatedfaces Před rokem

      @@Schnorzel1337 you're always going to confuse someone. There is no one practice that is accepted by hundreds of millions of people or the tens of millions of organizations that employ developers worldwide. Confusion indicates there is a team, if there is a team then why are you building the way you want to build?
      The consumer just needs to consume, the producer just needs to produce. How those two things work should be entirely decided upon by the individual teams who own each product. It will basically be decided by your distinguished engineer with 27 years of experience who still codes in notepad and hasn't used a library or package a single time in their life. When you work on a team you build as the team builds, not how a youtuber tells you to. That's why I argue the point, because doing things in a deadset way has always worked right? We've never created issues down the road by assuming there is a single solution to a problem in a literal turing-complete language right?
      and on the confusion thing...
      You're a developer on my team, if I can confuse you with the single responsibility principle then I don't know why you're on my team.

    • @xybersurfer
      @xybersurfer Před rokem

      @@explodatedfaces what problem does the wrapper solve? why even bother with null if you have to wrap it as an explanation? no one said anything about teams

  • @tobeypeters
    @tobeypeters Před rokem

    I've always just returned an empty array [].

  • @MixolydianMode
    @MixolydianMode Před rokem +5

    The type declared in the function is IEnumerable, instead of null you return Enumerable.
    Why?

    • @noss403
      @noss403 Před rokem +13

      IEnumerable is interface. Enumerable is class and has static methods for creating empty collection.

    • @MixolydianMode
      @MixolydianMode Před rokem

      @@noss403 thank you

  • @abeplus7352
    @abeplus7352 Před rokem +2

    No . That’s a bad assumption . Null checks are explicit and usually convey an error or an outstanding reason why you got a non zero value . A zero value ( empty list ) would mean query is successful but no records . A null return means couldn’t query or something . Nulls are useful .
    This whole obsession with “clean code” has people doing dumb shit like this.

    • @nickchapsas
      @nickchapsas  Před rokem

      No, that’s bad advice. Wanna null check? Fine, but code that follows this principle is by definition safer because it can’t cause an NRE

    • @abeplus7352
      @abeplus7352 Před rokem

      @@nickchapsas eh agree to disagree

    • @nickchapsas
      @nickchapsas  Před rokem

      Absolutely 🙂

  • @Baby4Ghost
    @Baby4Ghost Před rokem +1

    I fully disagree.
    A empty collection is NOT the same as a null. Just as a 'false' (nullable) boolean is not null.
    Null collection means: undefined, undecided, not set, not assigned collection.
    Null boolean means: undefined, undecided, not set, not assigned. (where the *undecided* is the most important part!!)
    Empty collections means, *decided* to select 0 items.
    False means, *decided* to select the false option.
    If there is no null option, how will you differentiate between decided and undecided/default values?
    The 'bloated' code doesnt exist, if you work like me with the fail fast (a.k.a. fail early) method, which IMHO, should be the way anyways if you dont like bloated nesting, regardless of null checks!

    • @chrono0097
      @chrono0097 Před 11 měsíci

      It's simple: An empty list and null convey the same amount of information: none, just return an empty one, if you need to return a list with also a state that means 'something is wrong and this is different from not having data' then you can make a class to return your list alongside erros that may have happened, or a tupple, or a struct
      Null has no meaning implicit or explicit, if your code is going to be read and used by other people, its good to make clear what it does

    • @Baby4Ghost
      @Baby4Ghost Před 11 měsíci

      @@chrono0097
      1. That is what I would call bloated code. Im not going to make a result class for every single method just because you dont want to use nullable.
      2. "An empty list and null convey the same amount of information: none"- No. Why is stated in my first text.
      "If there is no null option, how will you differentiate between decided and undecided/default values?"
      Its like I can see in the future :)
      I use nullable as I see fit.
      - If a value is required, its non-nullable.
      - If a value is not required, its nullable.
      - If a value is not required, but has a default value, its nullable.
      If you need to return data with meta information/states, you can use a result class with the appropriate properties (e.g. in case of API's). But not as base for all your code..

    • @peryvindhavelsrud590
      @peryvindhavelsrud590 Před 11 měsíci

      Nullability is quoted as the billion dollar mistake because it's used wrong by a lot of people. In the common example mentioned in the video, where i expect a set of items matching a query in another set, Enumerable.Empty is the correct case. As you state though, null is a valid result in a lot of other cases where you need to differentiate between the empty set and the undefined set for instance

    • @Baby4Ghost
      @Baby4Ghost Před 11 měsíci

      ​@@peryvindhavelsrud590 Yes, to that I can agree that you dont just make things nullable, you have to think about it (like most things). If you dont, you'll make mistakes, which might end in a billion dollar mistakes.
      But its more in what do you expect back from a call. If you expect results back or an empty results, then its not suppose to be nullable. Again, as its fit.
      You also use this when you say: "where i expect [..]".
      So I stand by my original point, use it as fit (based on requirements) not because of dev reasons.
      Its also very noticable how everyone conveniently doesnt answer my question but still argues for non-nullable.
      Its like you dont think its important to differenciate between customer decided- and undecided contracts/insurance papers/transactions, etc.

    • @peryvindhavelsrud590
      @peryvindhavelsrud590 Před 11 měsíci

      @@Baby4Ghost i actually thought I answered your question with the fact that I agreed null is one way to do exactly what you want. Another trending way is to return discriminated unions you could for instance return one of x, undecided and validation error. Actually, then you can distinguish between more states without needing exceptions as well.

  • @sadaja25
    @sadaja25 Před rokem

    Doesn't an empty collection allocate memory? Most devs return null in order to avoid adding GC pressure

    • @nickchapsas
      @nickchapsas  Před rokem +1

      Most devs return null because it’s convenient. And no, depending on the type of collection, an empty array or enumerables doesn’t allocate memory. I’ve covered this in another short

    • @sadaja25
      @sadaja25 Před rokem

      @@nickchapsas awesome, I'gonna look for that video. You are producing such a great content! Congrats 👏👏👏

  • @AhmadElkhouly
    @AhmadElkhouly Před 3 měsíci

    Why not just return new List() ?

  • @ajzack983
    @ajzack983 Před rokem

    Return [null];
    Return all the nulls

    • @vytah
      @vytah Před 7 měsíci

      Chaotic Evil

  • @monq02
    @monq02 Před rokem

    ... i mean..... you could just skip them.... right?

  • @BoyWithBike
    @BoyWithBike Před rokem

    Sorry but the language of my choice handles properly null array/slices/maps when trying to iterate over them

  • @vigneashselvaraj3592
    @vigneashselvaraj3592 Před rokem

    May I know what happens if a foreach ran on the returned varable?

    • @peryvindhavelsrud590
      @peryvindhavelsrud590 Před 11 měsíci

      If you run a foreach over any null collection, it will throw a NullReferenceException, if you on the other hand iterate with foreach on an empty collection, it will do no work as there are no items to iterate over.
      Edit: that means the code inside the foreach will be skipped, but control flow will continue after the loop as if all is good with the world.

  • @Dror872
    @Dror872 Před měsícem

    List?

  • @DarkSolidity
    @DarkSolidity Před rokem

    Very cool

  • @rivazmardani
    @rivazmardani Před rokem

    instead of returning null, return "I use arch btw" instead