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

2024 ж. 13 Мам.
16 806 Рет қаралды

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 KZhead 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

Пікірлер
  • 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. KZhead is aggressively deleting all links. If you wish to submit your repo for review, use this form instead: codinghelmet.com/go/code-review-request

    @zoran-horvat@zoran-horvat Жыл бұрын
  • Too bad there is no button to give 1000 likes at once. Thanks, Zoran, for your master classes.

    @kristianaranda@kristianaranda Жыл бұрын
    • Thanks!

      @zoran-horvat@zoran-horvat Жыл бұрын
  • 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.

    @jeremyjinglebell2762@jeremyjinglebell276217 күн бұрын
  • 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.

    @tdao9741@tdao9741 Жыл бұрын
  • i found you yesterday. Im literally crying watching your videos! IT'S BEAUTIFUL!! THANKS FOR YOUR AMAZING JOB!

    @michapaucki6627@michapaucki6627 Жыл бұрын
  • I built a similar `Option` for a similar thing, but I made it implement `IEnumerable` so it‘s compatible with Linq. Was quite nice.

    @rGunti@rGunti6 ай бұрын
  • 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!

    @tdao9741@tdao974110 ай бұрын
  • 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.

    @jonnroc@jonnroc Жыл бұрын
    • One tip: Just use language-ext. If you are starting in functional programming, do not try to implement your own monads.

      @Gio2k@Gio2k Жыл бұрын
  • 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.

    @aalasso2@aalasso2 Жыл бұрын
  • 这是非常好的视频,在中国这样的视频几乎没有(可能是我没找到),每天重复的开发功能,瞬间点亮了我。 谢谢

    @user-eh9ht6vz2q@user-eh9ht6vz2q Жыл бұрын
  • 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.

    @seriyezh@seriyezh Жыл бұрын
    • Thanks! I also plan to cover advanced topics with optional objects.

      @zoran-horvat@zoran-horvat Жыл бұрын
  • 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.

    @LuizADRMarques@LuizADRMarques11 ай бұрын
  • Great class and great idea. Thank you

    @albertoviceconti8579@albertoviceconti85793 ай бұрын
  • Excellent video, thank you!

    @BelaSzilagyi@BelaSzilagyi Жыл бұрын
  • 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

    @Darebit2k1@Darebit2k1 Жыл бұрын
  • Thanks Mr. Zoran for this unique interesting video your channel will hit 100 000 subscriber in no time

    @rpchost@rpchost Жыл бұрын
  • Great introduction!

    @muhamedkarajic@muhamedkarajic Жыл бұрын
  • 9:20 - Monad 13:20 - Functional c# course in Pluralsight

    @ivandrofly@ivandrofly8 ай бұрын
  • 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.

    @ZubriQue@ZubriQue Жыл бұрын
    • I can almost see it 😊

      @zoran-horvat@zoran-horvat Жыл бұрын
  • 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.

    @sinan720@sinan720 Жыл бұрын
    • 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.

      @zoran-horvat@zoran-horvat Жыл бұрын
  • Senior developers like this one who will push you to do your best. "I don't like that coding style" 😂💯

    @fredrickamoako@fredrickamoako11 ай бұрын
  • Keyword: "Reduce" example

    @ivandrofly@ivandrofly7 ай бұрын
  • 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.

    @KA-wf6rg@KA-wf6rg Жыл бұрын
    • 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.

      @zoran-horvat@zoran-horvat Жыл бұрын
  • As always, very insightful! Are there any pitfalls when used with entity framework core 7?

    @avishaybenshimol3064@avishaybenshimol3064 Жыл бұрын
    • I plan to make another video to show optional objects in an ASP.NET application with EF Core.

      @zoran-horvat@zoran-horvat Жыл бұрын
  • 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"?

    @ks1970in@ks1970in Жыл бұрын
    • 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.

      @zoran-horvat@zoran-horvat Жыл бұрын
  • 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. ❤‍🔥

    @livingdeathD@livingdeathD5 ай бұрын
    • 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.

      @zoran-horvat@zoran-horvat5 ай бұрын
  • Thanks for the video How can we map this type to the database using ef core for example?

    @tarekalkhalili3180@tarekalkhalili3180 Жыл бұрын
    • That is a bit longer story, which I plan to cover in one of the subsequent videos.

      @zoran-horvat@zoran-horvat Жыл бұрын
  • 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.

    @auronedgevicks7739@auronedgevicks77394 ай бұрын
    • 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.

      @zoran-horvat@zoran-horvat4 ай бұрын
    • 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.

      @chudchadanstud@chudchadanstud13 күн бұрын
  • 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.

    @redcrafterlppa303@redcrafterlppa303 Жыл бұрын
    • Before we extend the discussion, how do you know that the optional object is stored inside the outer object?

      @zoran-horvat@zoran-horvat Жыл бұрын
    • @@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.

      @redcrafterlppa303@redcrafterlppa303 Жыл бұрын
    • @@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.

      @zoran-horvat@zoran-horvat Жыл бұрын
    • @@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.

      @redcrafterlppa303@redcrafterlppa303 Жыл бұрын
  • 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?

    @SerhiiZhydel@SerhiiZhydel Жыл бұрын
    • 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.

      @zoran-horvat@zoran-horvat Жыл бұрын
    • @@zoran-horvat ok I see, then it's probaly more a web-developer tool. thanks for the clarification!

      @SerhiiZhydel@SerhiiZhydel Жыл бұрын
  • I thought Reduce generally meant combining the output from Map, but here it is used as an Else. Isn’t it?

    @zimpoooooo@zimpoooooo2 ай бұрын
  • 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 =)

    @vionoche@vionoche Жыл бұрын
    • You can't initialize _option as null with a struct

      @ar_xiv@ar_xiv Жыл бұрын
    • 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.

      @vionoche@vionoche Жыл бұрын
    • Yea, thats why Nullable is a struct. Writing extension methods for Nullable is better than creating Option type in my opinion

      @sinan720@sinan720 Жыл бұрын
  • Very elegant way to deal with that horrible null in the code , thank you

    @ralphmaasgmailcom@ralphmaasgmailcom4 ай бұрын
  • 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?

    @digitaldias@digitaldias Жыл бұрын
    • 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.

      @gileee@gileee Жыл бұрын
    • nowadays, more money is lost because of unmanageable code than on performance

      @geesysbradbury3211@geesysbradbury32119 ай бұрын
  • 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?

    @soverain@soverain Жыл бұрын
    • You can define another method (I usually call it Do), which optionally invokes an action.

      @zoran-horvat@zoran-horvat Жыл бұрын
    • @@zoran-horvat I guess this Do method should return the option as it is, so we can continue chaining?

      @soverain@soverain Жыл бұрын
    • @@soverain No, I mean the method would be defined on the Option itself, just like the Map method is.

      @zoran-horvat@zoran-horvat Жыл бұрын
    • Really, really interesting! Enlightning as a none functional C# developer! 👍

      @SirJohnK@SirJohnK Жыл бұрын
  • Love your videos. Quick question, why is option not a struct?

    @ShiyalaKohny@ShiyalaKohny Жыл бұрын
    • 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.

      @zoran-horvat@zoran-horvat Жыл бұрын
  • 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?

    @Alguem387@Alguem387 Жыл бұрын
    • 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.

      @zoran-horvat@zoran-horvat Жыл бұрын
  • 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

    @billy65bob@billy65bob Жыл бұрын
    • 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.

      @zoran-horvat@zoran-horvat Жыл бұрын
  • 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.

    @pmcgee003@pmcgee0033 ай бұрын
    • 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.

      @zoran-horvat@zoran-horvat3 ай бұрын
    • @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

      @pmcgee003@pmcgee0033 ай бұрын
  • 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.

    @davidtaylor3771@davidtaylor377111 ай бұрын
  • 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.

    @gr-gx4zy@gr-gx4zy Жыл бұрын
    • Try Elm. It’s a FE framework based on FP.

      @smwnl9072@smwnl9072 Жыл бұрын
  • Can we specify multiple property which may contain null value before using Map ?

    @manmohanmundhraa3087@manmohanmundhraa3087 Жыл бұрын
    • 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.

      @zoran-horvat@zoran-horvat Жыл бұрын
  • Is there a way to use this with just a normal constructor instead of lambdas and this create function?

    @ar_xiv@ar_xiv Жыл бұрын
    • 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?

      @zoran-horvat@zoran-horvat Жыл бұрын
  • 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();

    @Sanabalis@Sanabalis Жыл бұрын
    • 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?

      @zoran-horvat@zoran-horvat Жыл бұрын
    • @@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);

      @Sanabalis@Sanabalis Жыл бұрын
    • @@Sanabalis That is a useful variant.

      @zoran-horvat@zoran-horvat Жыл бұрын
  • Warning: M-word at 7.52

    @10199able@10199able Жыл бұрын
  • Actually, it was called Aristotle of Nikodimos - his father

    @1Eagler@1Eagler3 ай бұрын
    • You have a Greek name, is that how you know it? It is new information for me, I'll remember it. Thanks!

      @zoran-horvat@zoran-horvat3 ай бұрын
    • @zoran-horvat my name helped. And my age - started with Pascal.

      @1Eagler@1Eagler3 ай бұрын
  • 3:50 why not return empty? How do these classes are saved on database?

    @1Eagler@1Eagler3 ай бұрын
    • 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.

      @zoran-horvat@zoran-horvat3 ай бұрын
  • Cant you write extensions methods to T? that do Bind and reduce for you?

    @kleinpoe@kleinpoe6 ай бұрын
    • 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.

      @zoran-horvat@zoran-horvat6 ай бұрын
    • @@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... :-(

      @kleinpoe@kleinpoe6 ай бұрын
  • 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

    @f13775@f137759 ай бұрын
    • 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.

      @zoran-horvat@zoran-horvat9 ай бұрын
    • @@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!

      @f13775@f137759 ай бұрын
    • @@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.

      @zoran-horvat@zoran-horvat9 ай бұрын
    • @@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!

      @f13775@f137759 ай бұрын
  • 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)

    @anarhistul7257@anarhistul7257 Жыл бұрын
    • 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.

      @zoran-horvat@zoran-horvat Жыл бұрын
  • It remind me what they do in Rust.Also, they have something alike regarding exception handling there too.

    @alexander_nunezf@alexander_nunezf Жыл бұрын
    • Yes, in Rust everything is Option and Result. Exceptions (called panic in Rust) are what assertions are in dotnet and they terminate the process.

      @zoran-horvat@zoran-horvat Жыл бұрын
  • 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)`.

    @larryd9577@larryd9577 Жыл бұрын
    • 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 Жыл бұрын
    • In modern Java, unless you have many optional fields (which is a code smell) the best technique (especially if using records) is using a sealed class (or interface) with subclasses representing the presence or absence of fields. Then you can use an enhanced switch to handle different states. No nulls, no optionals, no problems. And, realistically, good Haskell does *not* plaster code with a ton of Maybe types because that sealed class trick has been standard Haskell from the beginning: data Author = FirstNameOnly String | FirstLast String String showAuthor :: Author -> String showAuthor (FirstNameOnly fname) = fname showAuthor (FirstLast fname lname) = fname ++ " " ++ lname It's true that Maybe is used in library code to represent the absence of a value, but that's because library code needs to be reasonably generic. A map lookup function needs to indicate a value was present or not because the map itself doesn't know what it's storing. But if you're modeling real things, your code is always clearer when it describes what things *are*, not what they might be or are not.

      @dispatch-indirect9206@dispatch-indirect9206 Жыл бұрын
    • @@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.

      @gileee@gileee Жыл бұрын
  • 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.

    @Astral100@Astral100 Жыл бұрын
    • 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.

      @gileee@gileee Жыл бұрын
  • Hmm, 15:40 still makes no sense to me.

    @thygrrr@thygrrr11 ай бұрын
    • 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.

      @alfflasymphonyx@alfflasymphonyx7 ай бұрын
  • 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();

    @ai3388@ai3388 Жыл бұрын
    • 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.

      @zoran-horvat@zoran-horvat Жыл бұрын
    • ​​@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.

      @ai3388@ai3388 Жыл бұрын
  • why stop here? use nullable optional of an optional everywhere, I bet it will reduce your code even further :)

    @guai9632@guai9632 Жыл бұрын
    • Or just continue using monads the way everybody else does for decades...

      @zoran-horvat@zoran-horvat Жыл бұрын
  • 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.

    @todortodorov2632@todortodorov263211 ай бұрын
    • Why would you return null?

      @zoran-horvat@zoran-horvat11 ай бұрын
  • Answer: Learn to program properly.

    @grantofat6438@grantofat6438 Жыл бұрын
    • 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.

      @zoran-horvat@zoran-horvat Жыл бұрын
  • 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.

    @raianmr2843@raianmr2843 Жыл бұрын
  • Why don't you build it yourself, we did it 3 years ago.

    @larryd9577@larryd9577 Жыл бұрын
    • To build what?

      @zoran-horvat@zoran-horvat Жыл бұрын
    • 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.

      @larryd9577@larryd9577 Жыл бұрын
  • 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.

      @ParkourGrip@ParkourGrip Жыл бұрын
    • 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.

      @zoran-horvat@zoran-horvat Жыл бұрын
    • 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`.

      @alxjones@alxjones Жыл бұрын
    • @@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.

      @zoran-horvat@zoran-horvat Жыл бұрын
KZhead