| 1 | """ |
|---|
| 2 | Languages have a special value to indicate "no object": |
|---|
| 3 | |
|---|
| 4 | Name Languages |
|---|
| 5 | ---- --------- |
|---|
| 6 | nil Cobra, Smalltalk, Objective-C |
|---|
| 7 | null C#, Java |
|---|
| 8 | NULL C, C++ |
|---|
| 9 | None Python |
|---|
| 10 | Nothing Visual Basic |
|---|
| 11 | |
|---|
| 12 | But Cobra's nil can only be applied when a type is "nilable" as indicated by a |
|---|
| 13 | question mark suffix such as "String?". Cobra then enforces how nilable types |
|---|
| 14 | are used with the upshot that run-time "null reference exceptions" almost |
|---|
| 15 | never happen in Cobra programs. |
|---|
| 16 | """ |
|---|
| 17 | |
|---|
| 18 | class Thing |
|---|
| 19 | |
|---|
| 20 | var _name as String # must be initialized |
|---|
| 21 | var _alternateName as String? # can be left nil |
|---|
| 22 | |
|---|
| 23 | cue init(name as String) |
|---|
| 24 | base.init |
|---|
| 25 | _name = name |
|---|
| 26 | |
|---|
| 27 | pro name from var |
|---|
| 28 | |
|---|
| 29 | pro alternateName from var |
|---|
| 30 | |
|---|
| 31 | |
|---|
| 32 | class Limits |
|---|
| 33 | """ |
|---|
| 34 | Tracks min/max limits which default to 0 and 10 respectively. |
|---|
| 35 | """ |
|---|
| 36 | |
|---|
| 37 | shared |
|---|
| 38 | var _defaultMin = 0 |
|---|
| 39 | var _defaultMax = 10 |
|---|
| 40 | |
|---|
| 41 | var _min as int? # start life as nil |
|---|
| 42 | var _max as int? |
|---|
| 43 | |
|---|
| 44 | cue init |
|---|
| 45 | base.init |
|---|
| 46 | |
|---|
| 47 | get min as int |
|---|
| 48 | if _min # checks for non-nil |
|---|
| 49 | return _min |
|---|
| 50 | else |
|---|
| 51 | return _defaultMin |
|---|
| 52 | |
|---|
| 53 | get max as int |
|---|
| 54 | # can use if-expression instead of if-statement |
|---|
| 55 | return _max ? _defaultMax |
|---|
| 56 | |
|---|
| 57 | |
|---|
| 58 | class ExampleCalls |
|---|
| 59 | |
|---|
| 60 | def printValue(v as Object) |
|---|
| 61 | # note that this method won't take nil because the arg is "Object" not "Object?" |
|---|
| 62 | print v |
|---|
| 63 | |
|---|
| 64 | def main |
|---|
| 65 | th = Thing('two') |
|---|
| 66 | th.alternateName = '2' |
|---|
| 67 | th.alternateName = nil # no problem since .alternateName is a String? |
|---|
| 68 | # th.name = nil # compiler error: cannot assign nil to non-nilable type |
|---|
| 69 | |
|---|
| 70 | .printValue(th.name) |
|---|
| 71 | |
|---|
| 72 | altName = th.alternateName # type inference determines that `altName` type is String? |
|---|
| 73 | # .printValue(altName) # compiler error: cannot pass nilable type where non-nilable expected |
|---|
| 74 | # two solutions: |
|---|
| 75 | if altName # checks for non-nil |
|---|
| 76 | .printValue(altName) # compiler understands this is okay |
|---|
| 77 | else |
|---|
| 78 | print 'alternate name is nil' |
|---|
| 79 | |
|---|
| 80 | # or typecast to non-nil ("x to !") for those times when you know the value will not be nil |
|---|
| 81 | altName = 'Two' |
|---|
| 82 | .printValue(altName to !) |
|---|
| 83 | |
|---|
| 84 | |
|---|
| 85 | class MoreInfo |
|---|
| 86 | |
|---|
| 87 | def foo |
|---|
| 88 | # you can also affect type inference by casting to nilable with "x to ?" |
|---|
| 89 | value = 0 to ? # type is "int?" |
|---|
| 90 | |
|---|
| 91 | # you can return nil in an if-expression which makes the type nilable |
|---|
| 92 | name = if(value and value <> 0, 'value', nil) # type is "String?" |
|---|
| 93 | if name, print name |
|---|
| 94 | |
|---|
| 95 | # you can coalesce with ? as a binary operator |
|---|
| 96 | displayName = name ? '(no name)' |
|---|
| 97 | print displayName |
|---|