tech

[English] [Japanese]

20. nil conditional operator

This time I will explain LuneScript's nil conditional operator.

Map access

For example, if you have the following Map data,

// @lnsFront: ok
let json = {
   "lv1": {
      "lv2": {
         "lv3": {
            "lv4": { 
               "lv5": {
                  "val": 1
               }           
            }        
         }     
      }  
   }
};

To access the val of lv5 you have to do something like this:

// @lnsFront: skip
if! let lv1 = json.lv1 {
   if! let lv2 = lv1.lv2 {
      if! let lv3 = lv2.lv3 {
         if! let lv4 = lv3.lv4 {
            if! let lv5 = lv4.lv5 {
               print( lv5.val );
            }        
         }     
      }  
   }  
}

Or you have to unwrap it like this:

// @lnsFront: skip
print( (unwrap (unwrap (unwrap (unwrap (unwrap json.lv1).lv2).lv3).lv4).lv5).val );

Either way, it's not good.

The nil conditional operator can be used to easily perform such nested nil checks.

nil conditional operator

Accessing the val of lv5 above using the nil conditional operator looks like this:

// @lnsFront: skip
print( json.lv1$.lv2$.lv3$.lv4$.lv5$.val );

It's pretty refreshing.

The nil-conditional operator, when placed immediately after a nilable expression, controls whether or not the nilable expression is nil or not.

If the nilable expression evaluates to non-nil, the subsequent expression is executed, and if the nilable expression evaluates to nil, the subsequent expression is not executed and the result of that expression is nil.

$[ is used to access the list, and $( is used to call the function.

For example:

// @lnsFront: ok
class Test {
   pub let val:List<int>;
   pub fn func():int {
      return 100;
   }
}
fn sub( test:Test! ) {
   print( test$.val$[1], test$.func$() );
}
sub( new Test( [ 1, 2 ] ) ); // 1 100
sub( nil ); // nil nil

In the above example, the sub() function accesses the Test class val list and func using the nil conditional operator. This allows access without unwrap.

Note

Using a nil conditional access always evaluates to nilable.

For example:

// @lnsFront: ok
class Test {
   pub let val:int;
}
fn sub( test:Test! ) {
   if! test$.val {
      print( _exp + 1 );
   }
}
sub( new Test( 10 ) ); // 11

In the above case, the val of the Test class is an int.

In the sub function in the above example, test$.val is used to access the nilable type Test class instance. At this time, the evaluation result of test$.val is int! instead of int.

summary

Nil conditional access makes it easy to do deeply nested unwraps.

Next time, we'll talk about module management.