Search Unity

How return null into a function that return a specific type ?

Discussion in 'Scripting' started by bali33, Jul 28, 2015.

  1. bali33

    bali33

    Joined:
    Aug 14, 2011
    Posts:
    232
    Hi guys,

    I have a List that contains instances of a custom struct :

    Code (CSharp):
    1. public struct MovieItem{
    2.  
    3.     public string name;
    4.     public MovieTexture movieTexture;
    5. }
    6.  
    7. public List<MovieItem> movies;
    Then I have a function that tries to retrieve a MovieItem based on the name property - if the MovieItem is found out then it is returned - if not I return null :

    Code (CSharp):
    1. public MovieItem GetMovieItemByName(string movieName){
    2.  
    3.     for (int i=0; i<movies.Count; i++) {
    4.  
    5.         if(movies[i].name == movieName){
    6.  
    7.             return movies[i];
    8.         }
    9.     }
    10.  
    11.     return null;
    12. }
    But Unity does not agree with that method and displays the following error message :

    I'm not use to C# and maybe there is an other way to return a null/empty or whatever value that means "null".

    Thank you
     
  2. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    Structs are what's called value types. Essentially, this means that when you pass them around, you pass a copy of the actual contents of the structs.

    Classes, on the other hand, are reference types. This means that when you pass those around, you pass a pointer to the actual object, and no copying of anything happens.

    The null value is a special value which means "this reference points at nothing". Since structs are not references, it doesn't make sense to reference a struct type as null.

    Now, this is awfully inconvenient - after all you often use null as a special value that signifies "there's nothing here" in your abstraction, and don't really think of it as a pointer. But, you'll have to live with it. There's some solutions:

    1: Turn your struct into a class. This will solve everything automatically for you, but remember that objects will have to be processed by the garbage collector. If you're creating a large amount of these MovieItems (thousands), this might become a problem. Otherwise this is the easiest way to go about it.

    As a general rule, if you have something that contains reference types (as opposed to only structs and primitives like integers), it should itself be a reference type, so I'd go with using a class here as MovieTexture is a class.

    2: Signify that there's no movie there in some other way. the usual way to do that would be to return default(MovieItem) instead of null. The default argument returns null for reference types, and a zero-value for structs. So wherever you'd check if the object returned was null, you check if it's equal to default(MovieItem) instead:

    Code (CSharp):
    1. public MovieItem GetMovieItemByName(string movieName){
    2.  
    3.     for (int i=0; i<movies.Count; i++) {
    4.  
    5.         if(movies[i].name == movieName){
    6.  
    7.             return movies[i];
    8.         }
    9.     }
    10.  
    11.     return default(MovieItem);
    12. }
    13.  
    14. //usage:
    15.  
    16. MovieItem myMovie = movieDatabase.GetMovieItemByName("Spider Man 2");
    17.  
    18. if(myMovie == default(MovieItem) {
    19.     BeSad();
    20. }
    21. else {
    22.     WatchMovie(myMovie);
    23. }
    3: use a nullable struct. Whenever you define a struct named "SomeStruct", the type "SomeStruct?" is a type that can either be a member of SomeStruct, or null. So your GetMovieItemByName method would look like:

    Code (CSharp):
    1. public MovieItem? GetMovieItemByName(string movieName){ ... }
    And you would be able to return null as much as you want. To get the actual MovieItem from the MovieItem?, there's a special .Value property you can use to get the actual movie:

    Code (CSharp):
    1. MovieItem? myMovie = GetMovieItemByName("Spider Man 2");
    2.  
    3.         if(myMovie == null) {
    4.             BeSad();
    5.         }
    6.         else {
    7.             WatchMovie(myMovie.Value);
    8.  

    Hope that helps!
     
    arkatir, Leohoran, PvtPuddles and 3 others like this.
  3. bali33

    bali33

    Joined:
    Aug 14, 2011
    Posts:
    232
    Hi,

    Thank you for this very accurate explanation - it's all clear now !!!

    Thank you
     
  4. bali33

    bali33

    Joined:
    Aug 14, 2011
    Posts:
    232
    Hi,

    I tried the default(StructName) solution but Unity does not agree when I try to compare the return struct and the default() :

    Code (CSharp):
    1. if(myMovie == default(MovieItem) {
    Unity console output :
    Any idea why ?

    Thanks
     
  5. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    Can you post the code? You're missing a ')' there, and the example doesn't contain '!=', which is what the error is about.
     
    Tihhoo likes this.