How to Avoid Null Reference Exceptions: Optional Objects in C#

แชร์
ฝัง
  • เผยแพร่เมื่อ 5 ก.ค. 2024
  • Are you tired of dealing with null reference exceptions in your C# code? In this video, I'll show you how to avoid null reference exceptions using optional objects in C#. Null reference exceptions can be frustrating to deal with and can lead to your program crashing. But fear not, because, with my expert tips and tricks, you'll be able to handle them with ease. I'll cover the basics of null reference exceptions, including how to fix and handle them. I'll also cover topics such as nullable vs. optional objects, will discuss the difference between nullable and optional objects, and how to use them to your advantage.⚡️❤️
    By the end of this video, you will have a clear understanding how to avoid the need for nulls, thus removing the threat of a NullReferenceException in C#, and how to use optional objects effectively.❤️
    My channel is dedicated to object-oriented programming, including C#, dotnet, and functional programming. I provide tutorials, tips, and tricks for programming in C#, making it easy for beginners and experienced programmers alike. Whether you're new to C# programming or a seasoned professional, my channel is the perfect resource for improving your programming skills. With Zoran Horvat, you'll have access to the best C# tutorials and programming resources to take your programming skills to the next level.❤️
    So, If you're tired of dealing with null reference exceptions in C# programming, then be sure to subscribe to our channel for the latest programming tips and tricks.🔥❤️
    ✅🔔Become a patron and get access to source code and exclusive live streams: / null-conundrum-c-81382208
    ✅🔔 Subscribe ► / @zoran-horvat
    ⭐ Learn more from video courses:
    Beginning Object-oriented Programming with C# ► codinghelmet.com/go/beginning...
    ⭐ Collections and Generics in C# ► codinghelmet.com/go/collectio...
    ⭐ Making Your C# Code More Object-oriented ► codinghelmet.com/go/making-yo...
    🗳 Pluralsight Courses ► codinghelmet.com/go/pluralsight
    📸 Udemy Courses ► codinghelmet.com/go/udemy
    ▬▬▬▬▬▬▬▬▬▬▬
    ⚡️ Have a look at our other Videos:
    👉 Other videos on this channel you may be interested in watching:
    Using GitHub Copilot to Write Complex Code | Step-by-step Tutorial ► • Using GitHub Copilot t...
    👉 Coding with GitHub Copilot - Beginner to Master | VS Code Demo ► • A Comprehensive Guide ...
    👉 What is Covariance and Contravariance in C# ► • What is Covariance and...
    How to Initialize a Clean ASP.NET Core Project with Entity Framework Core and Identity ► • How to Initialize a Cl...
    ⚡️Chapters:
    ▬▬▬▬▬▬▬▬▬▬▬
    ⌚ 0:00 Today's Topic: Optional Objects in C#
    ⌚ 0:58 How to Avoid Null Reference Exceptions
    ⌚ 17:53 Outro
    ▬▬▬▬▬▬▬▬▬▬▬
    #null #optionalobjects #csharp #dotnet #objectorientedprogramming #dotnet #zoranhorvat
    ▬▬▬▬▬▬▬▬▬▬▬
    ⭐ CONNECT WITH ME 📱👨
    🌐Buy me a Coffee ► ko-fi.com/zoranhorvat
    🗳 Pluralsight Courses ► codinghelmet.com/go/pluralsight
    📸 Udemy Courses ► codinghelmet.com/go/udemy
    📸 Join me on Twitter ► / zoranh75
    🌐 Read my Articles ► codinghelmet.com/articles
    📸 Join me on LinkedIn ► / zoran-horvat
    ▬▬▬▬▬▬▬▬▬▬▬
    👨 About Me 👨
    Hi, I’m Zoran, I have more than 20 years of experience as a software developer, architect, team lead, and more. I have been programming in C# since its inception in the early 2000s. Since 2017 I have started publishing professional video courses at Pluralsight and Udemy and by this point, there are over 100 hours of the highest-quality videos you can watch on those platforms. On my TH-cam channel, you can find shorter video forms focused on clarifying practical issues in coding, design, and architecture of .NET applications.❤️
    ▬▬▬▬▬▬▬▬▬▬▬
    ⚡️RIGHT NOTICE:
    The Copyright Laws of the United States recognize a “fair use” of copyrighted content. Section 107 of the U.S. Copyright Act states: “Notwithstanding the provisions of sections 106 and 106A, the fair use of a copyrighted work, including such use by reproduction in copies or phono records or by any other means specified by that section, for purposes such as criticism, comment, news reporting, teaching (including multiple copies for classroom use), scholarship, or research, is not an infringement of copyright." This video and our youtube channel, in general, may contain certain copyrighted works that were not specifically authorised to be used by the copyright holder(s), but which we believe in good faith are protected by federal law and the Fair use doctrine for one or more of the reasons noted above.
    ⭐For copyright or any inquiries, please contact us at zh@codinghelmet.com
  • วิทยาศาสตร์และเทคโนโลยี

ความคิดเห็น • 141

  • @zoran-horvat
    @zoran-horvat  ปีที่แล้ว +1

    Become a patron and get access to source code and exclusive live streams: www.patreon.com/posts/null-conundrum-c-81382208
    Send over the examples of your class designs that you wish me to review and, maybe, include in the future video on code redesign and refactoring.
    TH-cam is aggressively deleting all links. If you wish to submit your repo for review, use this form instead: codinghelmet.com/go/code-review-request

  • @kristianaranda
    @kristianaranda ปีที่แล้ว +43

    Too bad there is no button to give 1000 likes at once. Thanks, Zoran, for your master classes.

  • @tdao9741
    @tdao9741 ปีที่แล้ว +26

    I like that your lecture is about C# but sounds like I'm listening to an audio book of The Lord of The Rings. Like your courses on Pluralsight, great content as usual.

  • @michapaucki6627
    @michapaucki6627 ปีที่แล้ว +6

    i found you yesterday. Im literally crying watching your videos! IT'S BEAUTIFUL!! THANKS FOR YOUR AMAZING JOB!

  • @rGunti
    @rGunti 8 หลายเดือนก่อน +4

    I built a similar `Option` for a similar thing, but I made it implement `IEnumerable` so it‘s compatible with Linq. Was quite nice.

  • @jonnroc
    @jonnroc ปีที่แล้ว +15

    I've been skeptical of the Option type, that is until seeing this video. You've convinced me to establish an implementation of Option in my own code library. Thanks, Zoran.

    • @Gio2k
      @Gio2k ปีที่แล้ว +2

      One tip: Just use language-ext. If you are starting in functional programming, do not try to implement your own monads.

  • @tdao9741
    @tdao9741 ปีที่แล้ว +3

    This lecture is one that I occasionally revisited in the past weeks while dipping my toes in Haskell from the fundamentals knowing that I'll be a better programmer coding in the functional style. I initially encountered the difficulty understanding monad, but now thinking back I think the difficulty mainly came from how difficult virtually everybody says it is. You did a wonderful job explaining this beautiful and powerful concept. I smiled bigger and bigger after each revisit as I understood more and more and finally totally understood. Thank you!

  • @jeremyjinglebell2762
    @jeremyjinglebell2762 2 หลายเดือนก่อน +2

    Incredibly interesting video. Made me run it several days each time 10 minutes before I got lost or was forced to seek another video or missing part for me to understand. I will have to schedule another few days to re-watch and hopefully I start to get it later. Not easy to absorb such a stuff in one shot. I discovered other videos from Zoran and definitely going to watch them. I have to stop them often, lol. I like it though. Great content.

  • @aalasso2
    @aalasso2 ปีที่แล้ว +6

    Very nice video.
    The Pluralsight course sounds like a course I'd be interested in taking. I've had a subscription previously, but I didn't much like the platform overall.
    I wish the course were available as a standalone purchase.

  • @user-eh9ht6vz2q
    @user-eh9ht6vz2q ปีที่แล้ว +2

    这是非常好的视频,在中国这样的视频几乎没有(可能是我没找到),每天重复的开发功能,瞬间点亮了我。 谢谢

  • @LuizADRMarques
    @LuizADRMarques ปีที่แล้ว +1

    Very interesting, as usual. I had your Functional C# PS course in my to-do list for a while, I will definitely check it out now.

  • @seriyezh
    @seriyezh ปีที่แล้ว +5

    Thank you for a great video! I had this question in my mind for some time and I'm happy that you decided to cover this topic.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +3

      Thanks! I also plan to cover advanced topics with optional objects.

  • @BelaSzilagyi
    @BelaSzilagyi ปีที่แล้ว +2

    Excellent video, thank you!

  • @albertoviceconti8579
    @albertoviceconti8579 5 หลายเดือนก่อน +1

    Great class and great idea. Thank you

  • @muhamedkarajic
    @muhamedkarajic ปีที่แล้ว +1

    Great introduction!

  • @rpchost
    @rpchost ปีที่แล้ว +1

    Thanks Mr. Zoran for this unique interesting video your channel will hit 100 000 subscriber in no time

  • @MehediHasan-xd6rj
    @MehediHasan-xd6rj หลายเดือนก่อน +2

    Please take 1000 likes and thanks from me for your excellent Job. I am following you from the Pluralsight course. I have become a fan of your TH-cam videos.

  • @Darebit2k1
    @Darebit2k1 ปีที่แล้ว +2

    Usas mucho la programación declarativa pero sería muy bueno que nos explicaras porque viola o no, la ley de Demeter?
    Excelente explicación, gracias por compartir tus conocimientos

  • @ZubriQue
    @ZubriQue ปีที่แล้ว +5

    Nice video. I'm building a Web API controller and have to fight nulls a lot. The assignment says that some int/long values can be null, so it's even more a headache.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +1

      I can almost see it 😊

  • @redcrafterlppa303
    @redcrafterlppa303 ปีที่แล้ว +3

    14:30 I couldn't agree less to borrow your wording. Optional shouldn't be used as a storage object since it's designed to be short lived. If you know that an object will only live a few microseconds the compiler and the jit can make assumptions based on that.
    Java is currently working on big changes in the memory model them, when complete, allow you to constrict a class to help the compiler make those assumptions and optional is expected to get that treatment.
    Optional wrappers should be cleared as soon as possible since continuing operations in a function with a none variant is of no use in most cases.
    Also deeply nested optionals are always messy.
    To come back to your option monad. It does exactly what the c# operators do.
    Not being able to execute functions is just a wrong statement. You can call functions that expect nullable parameters and can be sure that they handle that correctly. If a function expect non nullable parameters you get a warning and should confirm non nullity before calling the function.
    In my opinion the explicit nullable types added to c# are totally enough to be a fully qualified as an option monad.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว

      Before we extend the discussion, how do you know that the optional object is stored inside the outer object?

    • @redcrafterlppa303
      @redcrafterlppa303 ปีที่แล้ว

      @@zoran-horvat in my most favorite option implementation from rust. It's part of the type system. A comparable solution in java would be this:
      sealed interface Optional permits Some, None {}
      final class Some implements Optional {
      public final T val;
      }
      final class None implements Optional {}
      I searched and found out the concept of a sealed hierarchy doesn't exist in c# that's why I displayed the basic implementation in java.
      To answer your question rather the optional is empty or not would be determined by pattern matching and instanceof checks.
      To be clear the java jdk implementation is similar to your version relying on nullability to determine emptiness which makes the wrapper completely unusable for non nullable types. (why shouldn't an int be optional?)
      If you are curious the implementation in rust looks like this:
      enum Option {
      Some(T),
      None
      }
      Yeah the language is just built for variant types.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว

      @@redcrafterlppa303 My implementation in C# is a value type, which is equivalent to Rust's struct implementation in every respect. Most notably, there is no difference (literally) in object's layout whether it contains a nullable field or a struct Option. And hence there is absolutely no reason to shy away from holding an option if need be.
      However, it is very important to note that the outer caller cannot tell whether the option is stored or calculated.
      Regarding the nullable references and tbe idea of functions receiving them, that would be a needless complication added as a burden to those functions. A function that knows what to do with an object, now must do two things out of nowhere. And repeat that code in every single function you make... That is precisely what monads are used for in practice, so to remove infrastructural code from the substantial one.

    • @redcrafterlppa303
      @redcrafterlppa303 ปีที่แล้ว +1

      @@zoran-horvat the version shown in the video is a reference type constrained to only contain refrence types.
      I don't know the object layout semantics of c# too well but in rust everything not explicitly marked as a reference is stored in place like ref structs in c# I think.
      If you Model the optional container as a value type that embeds itself in the containing object using the same or close to the same memory space as the content directly I agree with the statement that an optional can and should be used as the storage container as it then is a 0 cost abstraction.
      A refrence type option is always a costly thing as it is more likely to be on the heap the longer it lives.
      I think the biggest reason java suggests to use optional only as a return type is to make sure escape analysis can optimize the heap allocated optional away to just a stack value.
      About the part with the functions receiving optional/nullable parameters it's the functions choice. It basically says that the function makes this parameter "optional" and it's presence or absence is effecting the functions operation. If a function expects non null parameters the caller is required to ensure they are.
      Fun fact C#'s "string? " syntax is just syntactic sugar for the Nullable type which is equivalent to your option type only using operators instead of methods as it is a language feature instead of a library implementation.

  • @KA-wf6rg
    @KA-wf6rg ปีที่แล้ว +1

    I remember learning the optional object pattern from your videos on Pluralsight years ago. I really enjoyed using it but, perhaps because it requires a custom implementation with each new project/company I go to, I have fallen out of practice using it.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +2

      True. I would rather see a proper implementation in dotnet that includes automatic conversions to and from the underlying type and pattern matching, all supported natively.

  • @avishaybenshimol3064
    @avishaybenshimol3064 ปีที่แล้ว +1

    As always, very insightful! Are there any pitfalls when used with entity framework core 7?

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +6

      I plan to make another video to show optional objects in an ASP.NET application with EF Core.

  • @fredrickamoako
    @fredrickamoako ปีที่แล้ว +1

    Senior developers like this one who will push you to do your best. "I don't like that coding style" 😂💯

  • @auronedgevicks7739
    @auronedgevicks7739 6 หลายเดือนก่อน +1

    if you're wondering what the point of all this is.. it's because he doesn't want to do "if (x == null)" checks. So first they give us null reference with all it's confusing buts, and you can even roll your own with your private constructors or factories, or even take it to the next level with Monads. But ask yourself why not just check for null? it's a simple if statement. Well because Functional Programming demands that things exist, Functional Programming doesn't check for errors. Everything is just there so we can write beautiful expressions with the ugly bits hidden in Monads etc. There's nothing wrong with null checks if you're not writing functional code.

    • @zoran-horvat
      @zoran-horvat  6 หลายเดือนก่อน

      Actually, null references have one drawback compared to references to objects - they don't reference an object. If you need any information to complete the operation, then sorry. The information got lost in the process.
      It is not the principle in functional programming to always have an object. It is the principle in programming in general, and so it applies to object-oriented programming as-is.

    • @chudchadanstud
      @chudchadanstud 2 หลายเดือนก่อน

      Optionals exist in C++ and Rust. They exist so that you don't forget to check for null references and reassures the programmer that null references are accounted for, pretty much eliminating null reference errors all together.
      In all honesty there should be no nullable objects in C# or Java. It literally doesn't make sense since they're strongly typed and garbage collected.

  • @sinan720
    @sinan720 ปีที่แล้ว +3

    Why create a new type Option when you can just write an extension method for Nullable?
    Are you aware that "Reduce(T default)" already exists on nullable types, it is just named "GetValueOrDefault(T default)"....
    Also the examples you showed are a perfect case for pattern matching, which looks much more readable than chaining "Map" calls.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +1

      Option type is a monad, like Result type or a monad that handles I/O. It is possible to extend nullable reference types to bridge the gap to optional objects, but the same approach would fail in the very next step - monadic error handling.
      Regarding the GetValueOrDefault, it is defined on the Nullable struct which only applies to value types, and value types cover only a negligible portion of cases. Therefore, it does not apply to nullable types as a whole, namely the nullable reference types which are dominant in domain modeling.

    • @martinprohn2433
      @martinprohn2433 หลายเดือนก่อน

      @zoran-horvat
      Can you explain what you mean by "would fail in the very next step"?
      What I did in my code is creating an generic extensions method for Map and I could use nullable references like monads.
      (I also tried around with a manual monad class. But pattern matching etc. is much easier with nullable references than with monads.)
      Your Example with Book labes would work almost the same:
      ```csharp
      record Person(string FirstName, string? LastName = null);
      record Book(string Title, Person? author = null);
      string GetLabel(Person person) = person
      .LastName
      .Map(lastName => $"{person.FirstName} {lastName}")
      ?? person.FirstName;
      string GetBookLabel(Book book) => book
      .Author
      .Map(GetLabel)
      .Map(author => $"{book.Title} by {author}")
      ?? book.Title;
      ```
      So my Extension method is this:
      ```csharp
      [return: NotNullIfNotNull(nameof(defaultValue))]
      public static TOut? Map(this TIn? value, Func mapper, TOut? defaultValue = default)
      {
      if(value is null)
      {
      return defaultValue;
      }
      else
      {
      return mapper(value) ?? defaultValue;
      }
      }
      ```
      I don’t see why that would fail in the very next step.

  • @ks1970in
    @ks1970in ปีที่แล้ว

    brilliant. haven't tried - but hopefully should be easily mapped to DB field in EF core configurations. Also - what is the performance impact? can these be "inlined"?

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +1

      I am sure that compiler will consider inlining any of the operators. On top of that, you can use MethodImpl(MethodImplOptions.AggressiveInlining) attribute on methods to inficate the compiler that it should avoid making superfluous calls to the monad itself.

  • @tarekalkhalili3180
    @tarekalkhalili3180 ปีที่แล้ว +2

    Thanks for the video
    How can we map this type to the database using ef core for example?

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +5

      That is a bit longer story, which I plan to cover in one of the subsequent videos.

  • @livingdeathD
    @livingdeathD 7 หลายเดือนก่อน +1

    Excellent explanation, I only have one question, regarding performance and memory consumption, since I see that objects are constantly being created every time the map is called, if you can clarify a little I would appreciate it.
    ❤‍🔥

    • @zoran-horvat
      @zoran-horvat  7 หลายเดือนก่อน +2

      The option type can be implemented as a struct that wraps a nullable reference. In that case, there would be no allocation of new objects. Each assignment would be equal in performance to assigning a common reference. And yet, you would have all the benefits of a monadic type.

  • @SerhiiZhydel
    @SerhiiZhydel ปีที่แล้ว +1

    I watched your video very carefully and read your comments, and this Do/Map/Reduce pattern looks very interesting to me, so thanks for sharing this wonderful idea! But could you give a more full answer on if it is worth using it on the client side on frameworks like xamarin, wpf, or especially unity that eventually serializes almost all the types you create? And how do you handle serialization in this case? In json it will result in having an extra level nested object where user expects to see a field, right?

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +2

      That is a very good question. When it comes to transfer, serialization, persistence and other uses external to the model, I still use native types. When Option is implemented as a struct, then there is no overhead in converting it to and from a nullable variant of the contained type, for example. I am just doing that conversion on the boundary of the model so that only the model uses, and benefits from the use of optional objects.

    • @SerhiiZhydel
      @SerhiiZhydel ปีที่แล้ว +1

      @@zoran-horvat ok I see, then it's probaly more a web-developer tool. thanks for the clarification!

  • @digitaldias
    @digitaldias ปีที่แล้ว +7

    Only works internally. Using this pattern on any kind of API will just give grief, i.e, for an endpoint that delivers books and authors, this will just add complexity, and not reduce any. I find the nullable pattern way better as it is more explicit than hiding it into a construct from functional program that really shouldn't be applied in OOP. Did you try to bench this in terms of added heap allocations?

    • @gileee
      @gileee ปีที่แล้ว +2

      You wouldn't return the Book or Author objects in your response anyway. You'd have a Response contract that obviously would have all the fields reduced anyway.
      Functional programming has never been known for it's performance, only elegance.

    • @geesysbradbury3211
      @geesysbradbury3211 10 หลายเดือนก่อน

      nowadays, more money is lost because of unmanageable code than on performance

  • @davidtaylor3771
    @davidtaylor3771 ปีที่แล้ว +4

    We are never going to get more than a small number of developers using a technique like this unless it is more elegant and built into the language.

  • @heischono4917
    @heischono4917 หลายเดือนก่อน

    What about the performance, handling Option vs Nullable types?

    • @zoran-horvat
      @zoran-horvat  หลายเดือนก่อน +1

      Avoid collections of optionals and you'll be fine.

  • @ShiyalaKohny
    @ShiyalaKohny ปีที่แล้ว

    Love your videos. Quick question, why is option not a struct?

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว

      It can be. Actually, in the GitHub reoo, it is the struct. On the plus side, it takes less memory and CPU. On the negative side, it doesn't support pattern matching.

  • @vionoche
    @vionoche ปีที่แล้ว

    A great video, thank you! How do you think about using a struct instead of a class for the Option type? I suppose, the struct may consume less memory than the class. Anyway, I like this approach with Options, amazing code =)

    • @ar_xiv
      @ar_xiv ปีที่แล้ว

      You can't initialize _option as null with a struct

    • @vionoche
      @vionoche ปีที่แล้ว +2

      But in this Option we use nullable types. When we write `private T? _object = null;` it is the same sort as `private Nullable _object = null;`. Nullable types are structs themselves so you can use a struct of structs. I've just written an example with struct Options and it works.
      However, I've found an answer why using the struct Option is a bad idea:
      The memory layout of a nullable structure is just like that of the non-nullable version plus a boolean indicating whether there is a valid value. Compared to a class, a structure that contains nullable types will have an additional boolean in its memory layout for each of its nullable fields. That is why the struct Option will consume a little more memory than a class.

    • @sinan720
      @sinan720 ปีที่แล้ว

      Yea, thats why Nullable is a struct. Writing extension methods for Nullable is better than creating Option type in my opinion

  • @Alguem387
    @Alguem387 ปีที่แล้ว

    Is there any valid reason to not just use Option as a readonly struct?
    Since it dosent make sense to mutate it nad all it does is wrap a value when it wraps a reference it just holds it
    it being a class adds an extra level indirection, that dosent seem to be of any use.
    Im i missing something?

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +1

      In the GitHub repository I have implemented it as a record struct wrapping a nullable reference.
      That would improve performance, but at the expense of two issues. One, you cannot support optional value types and optional reference types with one type - the implementation leaks into the public API.
      The other issue is that, not being polymorphic, the struct Option cannot be a subject to pattern matching.

  • @gr-gx4zy
    @gr-gx4zy ปีที่แล้ว

    Does it make sense on front-end side to do something like this with data that comes from BE? I would like to get rid of null and undefined in typescript but not sure if that makes sense. I know JQuery did that long time ago.

    • @smwnl9072
      @smwnl9072 ปีที่แล้ว

      Try Elm. It’s a FE framework based on FP.

  • @zimpoooooo
    @zimpoooooo 4 หลายเดือนก่อน

    I thought Reduce generally meant combining the output from Map, but here it is used as an Else. Isn’t it?

  • @soverain
    @soverain ปีที่แล้ว +2

    I like this approach very much. I have a question: how would you go about using this option type with a function that does not return a value? Like updating a database entry. Would you always end the sequence by calling Reduce()? What if you can’t provide a default value but just need to exit the function?

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +3

      You can define another method (I usually call it Do), which optionally invokes an action.

    • @soverain
      @soverain ปีที่แล้ว

      @@zoran-horvat I guess this Do method should return the option as it is, so we can continue chaining?

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +1

      @@soverain No, I mean the method would be defined on the Option itself, just like the Map method is.

    • @SirJohnK
      @SirJohnK ปีที่แล้ว +1

      Really, really interesting! Enlightning as a none functional C# developer! 👍

  • @kelton5020
    @kelton5020 หลายเดือนก่อน

    I like that the caller doesn't have to check for nulls, but I feel like the tradeoff is it's not as intuitive or readable as null checks/coalescing.

    • @zoran-horvat
      @zoran-horvat  หลายเดือนก่อน +1

      It starts being intuitive when you accept function application as the principle. That is a giant leap towards monadic flows.

  • @billy65bob
    @billy65bob ปีที่แล้ว +2

    14:20 that's actually the thing I hate about Java, or rather how Java developers approach things.
    They'd have a Book class, and then a derived BookWithAuthor.
    Likewise they'd split Author into both Author and a derived AuthorWithLastname.
    Extrapolate this to a large code base, and you've got an insurmountable hierarchy I don't want to deal with.
    On a side note, couldn't you make Map and Reduce generic extensions, similar to LINQ, so you don't need the wrapper?
    i.e. something like:
    public static TResult? Map(this T? value, Func map) => value != null ? map(value) : null;
    public static T Reduce(this T? value, T defaultValue) => value ?? default

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว

      Traditional Java was exhibiting much of the issues connected with pure OOP - most notably bloated code and too many classes. It has changed iver the years to adopt more streamlined designs, but I am not sure if programmers are lagging behind these changes. I still see a lot of dirty Java code.
      Regarding nullable extensions, that is a viable option. The core idea is to wrap null tests into a monad and this remove them from code that operates on the object. Extension methods can implement that monad.

  • @DmitriNesteruk
    @DmitriNesteruk หลายเดือนก่อน +1

    The use of terminology here is not 100% correct, because normally `Reduce()` does a completely different thing. The correct term here would be something like `Otherwise()` or something to that effect. `Map()` is more correct though you could equally call it `Select()` (per LINQ terminology), `Take()` or something else. Also, in `GetLabel()`, the initial call to `person.` can throw if it's null, and this call isn't handled here by the Maybe monad.

  • @ar_xiv
    @ar_xiv ปีที่แล้ว

    Is there a way to use this with just a normal constructor instead of lambdas and this create function?

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว

      You can expose two constructors, or just one with a nullable argument, but that might be confusing to callers.
      Mapping and reducing, on the other hand, are meant to bind a function to the optional content. What else can we do but receive a Func delegate?

  • @manmohanmundhraa3087
    @manmohanmundhraa3087 ปีที่แล้ว

    Can we specify multiple property which may contain null value before using Map ?

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +1

      Things become progressively more complex when multiple optional objects are used in the same expression. To see it better, try to imagine the same expression with nullable references - that would grow more complex as well, but multiple branching instructions would be easier to imagine.
      One way to address the problem is to cut the problem into smaller pieces, implemented by one method each. A method would then only manage one optional object and produce a result, either another optional object, or a proper (non-optional) object. Then combine those smaller methods into a large expression.
      I use this design style of separating optional expressions into sub-expressions a lot.

  • @ivandrofly
    @ivandrofly 10 หลายเดือนก่อน

    9:20 - Monad
    13:20 - Functional c# course in Pluralsight

  • @Sanabalis
    @Sanabalis ปีที่แล้ว

    You made these Optional Objects really interesting and I'd love to use them. However, I am unsure on how to implement a specific use case. What if I have two (or more) optional values in the class, and I have to do 4 different things, depending if both values are present, just the first, just the second or neither. What would be the proper way of mapping/implementing that use case? Basically, how to implement the following (expanded for clarity):
    if (obj.a is null && obj.b is null) return n();
    if (obj.a is not null && obj.b is null) return a();
    if (obj.a is null && obj.b is not null) return b();
    return ab();

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +1

      That is the hard part about possibly missing objects. That same problem exists with any other representation, like nullable objects.
      What I normally do when I face a pair of optional objects is to define an operation where only one (e.g. the second one) is optional, as an intermediate step.
      Then resolve the first object and, if exists, call this intermediate operation. That operation, in turn analyzes the second object and applies the definite two-argument function to both objects on success.
      Alternative is to transform the pair of optional objects into an optional pair, using another helper operator.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว

      P.S. There is another aspect of the question you asked: How did you get into the position of having two optional objects? Why didn't the operation resolve the first object before stepping to fetch the second one, so to terminate early if the first object is missing?

    • @Sanabalis
      @Sanabalis ปีที่แล้ว +2

      @@zoran-horvat I just added the following into the Option class (and similar to ValueOption):
      public Option OrElse(Func orElse) => _value is not null ? this : orElse();
      This made it easy to handle missing objects. Example code:
      ItemOne.Map(WithFirst).OrElse(WithoutFirst);

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว

      @@Sanabalis That is a useful variant.

  • @pmcgee003
    @pmcgee003 5 หลายเดือนก่อน

    I very much like your two videos on Option that I have seen .. but I have an issue with your naming of Reduce for OrDefault.
    Reduce is well established (as in Map-Reduce) for repeatedly applying a binary operator T->T->T
    I'd also, personally, rather see bind named as such, given it's really Map followed by Join.

    • @zoran-horvat
      @zoran-horvat  4 หลายเดือนก่อน

      This naming follows from the observation that an optional object is nothing but a sequence with no more than one item in it, a sequence with a constraint. Therefore, the Map-Reduce principle applies to it natively.

    • @pmcgee003
      @pmcgee003 4 หลายเดือนก่อน

      @zoran-horvat I have to disagree. It's really a mapping of a function that returns Just(x) or Default.
      Reduce wouldn't change type. It would be T+T -> T

  • @1Eagler
    @1Eagler 5 หลายเดือนก่อน +1

    Actually, it was called Aristotle of Nikodimos - his father

    • @zoran-horvat
      @zoran-horvat  5 หลายเดือนก่อน +1

      You have a Greek name, is that how you know it? It is new information for me, I'll remember it. Thanks!

    • @1Eagler
      @1Eagler 5 หลายเดือนก่อน +1

      @zoran-horvat my name helped.
      And my age - started with Pascal.

  • @ralphmaasgmailcom
    @ralphmaasgmailcom 5 หลายเดือนก่อน +1

    Very elegant way to deal with that horrible null in the code , thank you

  • @kleinpoe
    @kleinpoe 8 หลายเดือนก่อน

    Cant you write extensions methods to T? that do Bind and reduce for you?

    • @zoran-horvat
      @zoran-horvat  8 หลายเดือนก่อน +1

      That is possible, but you would have to implement it separately for nullable value types, and the dolution is also limited to one object. For instance, that wouldn't work when implementing the Either type, which is, in a way, an extension to the idea of optional objects. It is therefore common to implement monads as full-blown types.

    • @kleinpoe
      @kleinpoe 8 หลายเดือนก่อน +1

      @@zoran-horvat Yes that is unfortunate. I came across your pluralsight courses and you motivated me to explore the functional world and it is great. Thank you for that. Unfortunately my coworkers are not very incentivized to introduce the functional monads to our code, they rather want to use the nullable reference types... so I am looking for ways to still get at least some functional tools. But it seems that I will not get the either monad then... :-(

  • @1Eagler
    @1Eagler 5 หลายเดือนก่อน

    3:50 why not return empty?
    How do these classes are saved on database?

    • @zoran-horvat
      @zoran-horvat  5 หลายเดือนก่อน +1

      Empty string is not the same as no string - it would indicate that the string exists, and its value is empty.
      Optional objects can be saved to nullable fields in the database record, because that is the way relational databases are handling nonexistent values.

  • @10199able
    @10199able ปีที่แล้ว +4

    Warning: M-word at 7.52

  • @anarhistul7257
    @anarhistul7257 ปีที่แล้ว +3

    When would you consider this pattern overkill?
    I could see it used almost everywhere while not always worth the cost.
    I could just incapsulate GetLabel as a function on the object without the use of Option with some basic null checks.
    While not stopping me from accessing null properties as long as teammates aren't idiots this works just fine. (as long as they're not idiots)

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +5

      Any proper domain model should avoid depending on null in my opinion, and that is not the question of someone not being an idiot. Simply put, null carries no information. It is not telling anything in terms of the domain. And, on top of that, it is prone to design and runtime errors when programmers propagate nullable references through the entire domain only to keep the compiler quiet.
      If you were a Rust programmer, you wouldn't even ask that question. There, the entire language is driven by Option and Result types that are equivalent to Maybe and Either types in Haskell, for instance - and nobody ever complained about that!
      Working with optional objects in domain modeling is the state of the mind. Once you switch to that mode, you will never want to use a null in modeling again. It's not just me. I have testimonials from several colleagues, members of teams I led in the past, who were reluctant to accept that at first, but a year later they come to me saying: Never nullable reference again.
      Nullable references remain in non-OO parts of the model: Persistence model, UI (if no other solution), serialization, etc.

  • @alexander_nunezf
    @alexander_nunezf ปีที่แล้ว +1

    It remind me what they do in Rust.Also, they have something alike regarding exception handling there too.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว

      Yes, in Rust everything is Option and Result. Exceptions (called panic in Rust) are what assertions are in dotnet and they terminate the process.

  • @f13775
    @f13775 11 หลายเดือนก่อน

    Zoran, greetings from Macedonia! Why just not to introduce FullName method and incapsulate the logic of getting the full name into the Author object? it looks way more complex, to use map+reduce just to get rid of the null, I understand that this is just simple example, would be great if you can show real production code where this complexity is pay off

    • @zoran-horvat
      @zoran-horvat  11 หลายเดือนก่อน

      Mainly because there are multiple pieces of logic that pertain to the same piece of data. You would normally return an optional object from a method or a property getter and then leave mapping to the implementer of whatever logic is needed.

    • @f13775
      @f13775 11 หลายเดือนก่อน

      @@zoran-horvat Thank you for response Zoran, and from your experience where in application you would typically implement such approach ( maybe from your experience working on previous real production projects where you implemented such logic ?) Thank you!

    • @zoran-horvat
      @zoran-horvat  11 หลายเดือนก่อน

      @@f13775 Actually, that is a very frequent case in any domain. Think of any situation where a method would return a nullable type, and that is a viable case for optional objects.

    • @f13775
      @f13775 11 หลายเดือนก่อน

      @@zoran-horvat will try to implement this as part of refactoring in our pretty legacy project, hope the Optional object will pass code review from my team peers:), thank you for you feedback!

  • @GeoffInfield
    @GeoffInfield 27 วันที่ผ่านมา +1

    Java has Optionals and moving to C# is horrifying. The inconsistent behaviour and blurring of lines is apalling. In Java you're treated like an adult so everything is precise - int is primitive/value and Integer is a class/reference, ditto boolean/Boolean - but in c# we have int which is apparently a primitive/value that defaults to zero and has a constructor like an object/reference so which IS it? String - sorry, string - also has a constructor but it DOESN'T default to "" so wtf? Java String is only an object/reference and it behaves like every other object/reference, no guessing. I'm hating C# so much 😢

    • @zoran-horvat
      @zoran-horvat  26 วันที่ผ่านมา

      Are you sure "hate" is the right choice of a word. If you invested a bit into understanding these differences, you would surely find that Java doesn't have the definition of types passed by value and has no definition of generic types.
      What you call "precision" in Java is the only way there is. And so you will find all sorts of issues due to those shortcomings that were never solved (but should have been). Try to allocate a generic array and then specialize it to ints. Is that 10 lines of code in Java and execution time going 40x up? That is not "precision".

  • @larryd9577
    @larryd9577 ปีที่แล้ว +1

    The Java guidelines recommend holding null in fields instead of options. You shouldn't care what the state is, that is why it is private. :) And return from its getter an empty optional. Calculating sounds so expensive, when in essence it returns a static EMPTY object, or wraps the result in a low footprint wrapper and all by calling just one function `Option.ofNullable(_state)`.

    • @gileee
      @gileee ปีที่แล้ว

      People in java mostly use Lombok anyway to implement getters and setters and Lombok doesn't support getters that return Optional. Seems to be because the devs think it's bad code. It seems they consider Optional itself to be bad code for some reason. So unless you want to write all those getters and setters in full by hand every time, good luck.
      Considering it's mostly accepted in the Java world that you shouldn't have Optional in fields, it seems the "easiest" way would be to call Optional.ofNullable by hand whenever you access a nullable field.

    • @gileee
      @gileee ปีที่แล้ว

      @@dispatch-indirect9206 Handling "presence or absence" of fields with derived classes only gets you a million classes in your code. You should rarely have more than 1 level of inheritance.

  • @Astral100
    @Astral100 ปีที่แล้ว +2

    Unfortunately this is very complex for most developers. In my experience many developers struggle even with basic concepts. If I were to write a code like this it will become much harder to read and understand for other/future developers. (Who are usually not very bright at the best of times)
    I believe writing a simple (to read and understand) code is much more important that optimising the code to this degree.

    • @gileee
      @gileee ปีที่แล้ว +3

      Those junior devs will write horrible code anyway and need a lead dev to manually review their pull request until they learn no matter what kind of style or architecture you use. There's no getting around that. They need a mentor.
      The Maybe object just hides and even removes some superfluous null checks that permeate all codebases. It also removes the need to think about naming some variables inside functions since you just chain Map calls.

  • @ivandrofly
    @ivandrofly 9 หลายเดือนก่อน

    Keyword: "Reduce" example

  • @guai9632
    @guai9632 ปีที่แล้ว

    why stop here? use nullable optional of an optional everywhere, I bet it will reduce your code even further :)

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +2

      Or just continue using monads the way everybody else does for decades...

  • @ai3388
    @ai3388 ปีที่แล้ว

    0. Your function GetLabel contains an error, last name can be empty. simple and easy to read function can be: string GetLabel(Person p) => $"{p?.first} {p?.last}".Trim();
    1. too much boilerplate code with optional
    2. functional way for the simplest code looks unnatural in c# and it will be more ugly with more complex program. code is written once and read many times.
    3. memory overhead. let's imagine we have 1M records.
    4. we significally complicate the code for the sake of compiler warnings.
    p.s. and i dont think that nullable reference type is a good idea. Especially when we have null forgiving operator.
    #nullable enable object? nullable = null; object nonNullable = nullable!; var deref = nonNullable.ToString();

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว

      Optional objects are useful in a functional design where everything that is important already has a function that holds it. In that case, an operation on an optional object simply applies a preexisting function, making code shorter and more readable than the variant based on branching.
      Memory overhead problem is completely removed with a struct option.

    • @ai3388
      @ai3388 ปีที่แล้ว

      ​​@zoran-horvat yes, they are useful. i thought a little about these functions(map, reduce in this case) as the feature of c# for nullable types, it makes sense. But without additional class.

  • @todortodorov2632
    @todortodorov2632 ปีที่แล้ว

    But finally the Reduce method can return null and the client code will be forced to check if the result is null before using it. I do not see many sense using this implementation of Option. I prefer using the way when the option wraps the object in a collection with one element and then execute an action looping through the collection elements. I think I saw it in one of your Pluralsight videos many years ago.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +1

      Why would you return null?

  • @raianmr2843
    @raianmr2843 ปีที่แล้ว

    That tweet about not wanting to have two ways to do something is kinda hilarious because there're like - not two - but three or more ways to do absolutely anything and everything in C#. C# even pioneered some of the weaponry that'd later be used to divide entire libraries into multiple worlds like async-await, to name one.
    That Java convention is controversial but has some truth/insight to offer. Java doesn't have non-nullable reference types. The compiler literally cannot help you in most cases and your best bet is to sprinkle your code with third-party annotations, and pray and hope that your IDE picks things up from there on. So, there's an equally funny and depressing chance that a variable of Optional itself is null. As a result, some Java experts just decided to ignore this botched implementation of what is otherwise an excellent pattern and told people to pretend it doesn't exist. Others, however, salvaged what is there and chose to keep using for documentation and quality-of-life purposes.

  • @thygrrr
    @thygrrr ปีที่แล้ว

    Hmm, 15:40 still makes no sense to me.

    • @alfflasymphonyx
      @alfflasymphonyx 8 หลายเดือนก่อน

      I kind of agree with you. I understand the principle and the use of Option. However, I believe the issue might be the naming of functions which then used in the code renders the readibility more difficult.

  • @grantofat6438
    @grantofat6438 ปีที่แล้ว

    Answer: Learn to program properly.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +1

      Speaking of programming properly, there was a guy who explained (using quite strong language) that it is "programmer's duty to properly deallocate memory in C++". The result of accidentally not doing so, in that particular case, was 70 people dead by the end of the day.
      I would argue that you never programmed a nuclear plant or anything of that sort before throwing the term "program properly" into the discussion.

  • @larryd9577
    @larryd9577 ปีที่แล้ว

    Why don't you build it yourself, we did it 3 years ago.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว

      To build what?

    • @larryd9577
      @larryd9577 ปีที่แล้ว +3

      I mean for the fact, that the C# devs are not ready to support options, but you did it in the end. Sorry should have watched it till the end.

  • @ParkourGrip
    @ParkourGrip ปีที่แล้ว +1

    I am sure the map reduce pattern can be used with nullable values too. In Kotlin i would do nullableVariable?.let { it.someProperty } ?: defaultValue . I'm not super familiar with C# but im sure that you can implement your own let function from Kotlin if it does not already exist in the standard liberary. The only real advantage i see with Optional values is for things like storing optional values in a map. For example when we have a Map the return value of the map.get(key) method is going to be String?. But we have no idea if the returned value is null because null is stored in a map or because the key is not found inside the map. When using optionals, the map would be of type Map and the return type would be of the map.get would be Option. Now everything is clear from the return value.

    • @ParkourGrip
      @ParkourGrip ปีที่แล้ว

      "let" is just a function that takes a lambda expression as a argument and returns the value that the lambda expression returned. "it" is a implied default name of the single argument lambda in kotlin. You could write nullableVariable?.let { it -> it.someProperty } ?: defaultValue . It's the same thing.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว

      You can implement such a function in C# as well, as an extension to a nullable reference.
      One problem with that is that it cannot support value types consistently.

    • @alxjones
      @alxjones ปีที่แล้ว

      I really hate the idea of storing optional/nullable values in a map. A fundamental feature of a map is that a key exists if and only if a value exists on that key. I would re-evaluate the decisions that lead to the choice to break that feature before trying to use it to justify a different approach to null safety.
      In the event that you do need to distinguish between multiple fail-states, neither nullable nor optional is going to do what you want. Instead, you should be using a Result monad, e.g. from `kotlin-result`.

    • @zoran-horvat
      @zoran-horvat  ปีที่แล้ว +1

      @@alxjones I agree with you. In my opinion, not having an object mapping to a key is equivalent to mapping that key to null or some other indication that the object is missing, hence storing optional objects into a map is an oxymoron.
      On top of that, C# dictionary throws if the key is null, which I also agree with.