| 1 | = Variables = |
| 2 | |
| 3 | Cobra supports the normal range of variables |
| 4 | * Local Variables (lexically scoped) |
| 5 | * Instance Variables |
| 6 | * Method parameter Variables |
| 7 | * Properties |
| 8 | * Class or shared/static Variables |
| 9 | |
| 10 | Variables are statically typed but typing can be done explicitly (and optionally) with a declarative |
| 11 | "as clause" otherwise the variables type is inferred from initialization or first assignment or use. |
| 12 | Static typing allows cobra to be fast in execution, Type inference makes static typing bearable. |
| 13 | |
| 14 | |
| 15 | Variables are normally 'early bound' - typed at (first) use or declaration.[[BR]] |
| 16 | Variables can be dynamically typed (untyped) or 'late bound' by explicitly giving them |
| 17 | (or for some variables allowing them to default to) the '''dynamic''' type. |
| 18 | |
| 19 | |
| 20 | == Local Variables == |
| 21 | |
| 22 | Local variables are created and used within a method. [[BR] |
| 23 | They are used for temporary storage or calculation and are named starting with a leading |
| 24 | lowercase letter (no leading underscores or punctuation). |
| 25 | |
| 26 | They come into existance on first assignment unless explicitly declared |
| 27 | but are created local to the '''method''' they appear in (not just the block they |
| 28 | might have been first used in). [[BR]] |
| 29 | A compiler error will be generated if a local variable is used (read) before it |
| 30 | is created (initialized). |
| 31 | |
| 32 | Local variables can be explicitly typed if desired otherwise they infer their type from the |
| 33 | type of what they are assigned from. |
| 34 | |
| 35 | {{{ |
| 36 | s = "name:" # s is a String since thats what it is assigned from |
| 37 | greet = 'hello" + 'Mike.' # also a String since the assignment is a (String) expression |
| 38 | |
| 39 | i = 99 # i is an int (int32) since thats what 99 is |
| 40 | iu = 99_u8 # iu is an unsigned 8 bit int from the literal suffix on 99_u8 |
| 41 | |
| 42 | s1 as String = 'xxx' # redundant 'as TYPE' clause since assigned from a String anyway |
| 43 | |
| 44 | i1 as int # declaration without initialisation - defaults to the default value for the type (0 in this case) |
| 45 | |
| 46 | |
| 47 | }}} |
| 48 | |
| 49 | |
| 50 | Local variables of Reference types should generally be assigned to, to create and type them. |
| 51 | {{{ |
| 52 | s as String # generates a compiler error |
| 53 | # needs to be |
| 54 | # s as String? |
| 55 | |
| 56 | s = 'string value' |
| 57 | print s |
| 58 | }}} |
| 59 | |
| 60 | Non-primitive (Reference) typed variables, if declared and not initialised [[BR]] |
| 61 | need to be declared as nilable since they will default to the default-value for [[BR]] |
| 62 | a reference type which is nil (null) and if they're not nilable they can't have a nil value. |
| 63 | |
| 64 | Idiomatically in cobra it's best to create local variables by first use (an assignment) [[BR]] |
| 65 | rather than an explicit type declaration. |
| 66 | |
| 67 | |
| 68 | Sometimes though you need a variable to be typed differently (usually wider) than what it is [[BR]] |
| 69 | assigned from. To do this you can explicitly type the variable with an 'as clause' on first [[BR]] |
| 70 | use or cast (upcast) the initial value to the desired type. |
| 71 | |
| 72 | {{{ |
| 73 | space = 32_u8 |
| 74 | ispace as int32 = space |
| 75 | # or |
| 76 | ispace = space to int32 |
| 77 | |
| 78 | enclosure as Shape = Circle() |
| 79 | # or |
| 80 | enclosure = Circle() to Shape |
| 81 | }}} |
| 82 | |
| 83 | |
| 84 | == Instance Variables == |
| 85 | |
| 86 | Instance variables are variables associated with a class instance. [[BR]] |
| 87 | They encapsulate the state of the instance object [[BR]] |
| 88 | They must be declared (using the '''var''' keyword in a class/structure/interface definition) |
| 89 | but they too can be explicitly typed or have their type inferred from being initialised in |
| 90 | the declaration. [[BR]] |
| 91 | Like method parameter variables, if untyped and uninitialised, their type defaults to type '''dynamic'''. |
| 92 | |
| 93 | Instance variables default to public access. [[BR]] |
| 94 | If named with a leading '_' they default to protected access, with double leading '_' to private access. [[BR]] |
| 95 | Accessibility may be explicitly specified otherwise or overridden with an 'is clause' specifying one |
| 96 | of 'public', 'protected', 'private'. |
| 97 | |
| 98 | {{{ |
| 99 | class VarEG |
| 100 | var count = 0 # type inferred from initial value (int32) |
| 101 | var age as int # explicitly typed to int (int32) initial value default value for int (0) |
| 102 | |
| 103 | var _name as String # explicitly typed to String - nil value, private |
| 104 | var _definition as INamedNode? |
| 105 | |
| 106 | var other is private # dynamic type, explicitly private |
| 107 | |
| 108 | # Properties |
| 109 | pro defn as String # String Property |
| 110 | get |
| 111 | if not _definition |
| 112 | return 'No Defn' |
| 113 | return _definition.name |
| 114 | set |
| 115 | assert value.name |
| 116 | _definition = value |
| 117 | |
| 118 | pro name from _name # Read-write String Property from _name |
| 119 | |
| 120 | get repr as String # Read-only String property - synthesized |
| 121 | return '[_name]_[.age]' |
| 122 | |
| 123 | # class Variable |
| 124 | var nItems as int is shared |
| 125 | |
| 126 | }}} |
| 127 | |
| 128 | Unlike local variables, explicitly typed instance variables without an initial value given need |
| 129 | not be declared nilable unless they are intended or allowed to have a nil value after the |
| 130 | class instance initializer has run.[[BR]] |
| 131 | Instance variables that are not nilable will emit a runtime error if they have a nil value |
| 132 | at the end of the initializer execution. |
| 133 | |
| 134 | In code, instance variables are accessed with a leading 'this.' or just '.'. [[BR]] |
| 135 | (idiomatically and preferably just a leading '.').[[BR]] |
| 136 | The leading '.' is unnecessary if the instance variable name has a leading '_'. [[BR]] |
| 137 | (These are unambiguously instance variables as local variables cannot be declared with |
| 138 | leading underscores.) |
| 139 | |
| 140 | {{{ |
| 141 | # Initializer/Ctor |
| 142 | cue init( age as int, name as String) |
| 143 | .age = age |
| 144 | _name = name # ok _name now initialised and non nil |
| 145 | .other = .calcOther(name, age) |
| 146 | .nItems += 1 |
| 147 | |
| 148 | # A method |
| 149 | def rename(nuName as String) |
| 150 | .count += 1 # instance variable |
| 151 | calcName = nuName + '_[.count]' # local variable (String) |
| 152 | .name = calcName # change instance variable |
| 153 | }}} |
| 154 | |
| 155 | In the initializer, instance variable _name is now initialised, [[BR]] |
| 156 | _definition is nil but thats allowed since its declared nilable. |
| 157 | |
| 158 | |
| 159 | == Method parameter variables == |
| 160 | |
| 161 | Methods (initializers, etc) in a class may be declared to take parameters. [[BR]] |
| 162 | These can be optionally explicitly typed. If method parameters are not explicitly typed they |
| 163 | are assumed to be the '''dynamic''' type. |
| 164 | |
| 165 | Method parameter variables are named the same way as local variables ( leading lowercase letter) |
| 166 | and are also local only to the method they are on. [[BR]] |
| 167 | Calls to the methods convey the args given in the call to the (formal) parameter names in the order |
| 168 | declared on the method for use in the called method. |
| 169 | |
| 170 | {{{ |
| 171 | |
| 172 | # call to create VarEg instance |
| 173 | t = VarEG( 157, 'hops') |
| 174 | #... |
| 175 | t.rename('hopscc') |
| 176 | }}} |
| 177 | |
| 178 | In the initializer call parameter variables |
| 179 | * age <- 157 |
| 180 | * name <- 'hops' |
| 181 | in method call rename, parameter variables |
| 182 | * nuName <- 'hopscc' |
| 183 | |
| 184 | == Properties == |
| 185 | |
| 186 | Properties are a construct for external change or access to a classes state |
| 187 | (class or instance variables) mediated by some code. [[BR]] |
| 188 | They can be a simple passthrough to a possibly otherwise inaccessible class variable (field) or |
| 189 | anything else doable in a method. |
| 190 | |
| 191 | The major difference/advantage is that to calling code they are written to appear exactly like a |
| 192 | class variable access or mutation (no punctuation or boilerplate for method calls) so all the |
| 193 | description for instance variables applies. |
| 194 | |
| 195 | {{{ |
| 196 | |
| 197 | t = VarEG( 492, 'hops') |
| 198 | oldDefn = t.defn # local var oldDefn <- 'No defn' |
| 199 | oldName = t.name # local var oldName <- 'hops' |
| 200 | t.name ='hopscc' |
| 201 | |
| 202 | t.defn = .makeDefn(t) |
| 203 | print t.repr # prints 'hopscc_492' |
| 204 | |
| 205 | }}} |
| 206 | |
| 207 | == Class Variables == |
| 208 | |
| 209 | Class (or shared or static) variables are like instance variables but they are associated with |
| 210 | the class rather than each instance of a class. |
| 211 | They are declared like instance variables except that they have the modifier 'shared'. |
| 212 | Class variables can be accessed through a class instance or using the className |
| 213 | otherwise all the description of instance variables applies. |
| 214 | |
| 215 | {{{ |
| 216 | # Note that nItems is incremented in the initializer so it has a count of the |
| 217 | # number of instances made |
| 218 | |
| 219 | nItems = VarEG.nItems |
| 220 | print 'number Of VarEg instances made ' + nItems |
| 221 | |
| 222 | nullVarEG = VarEg(0, '') |
| 223 | assert nullVarEG.nItems == nItems + 1 # access class vars through instance or className |
| 224 | }}} |
| 225 | |
| 226 | |
| 227 | |
| 228 | == Notes == |
| 229 | |
| 230 | == See Also == |
| 231 | |
| 232 | |
| 233 | [wiki:LanguageTopics Back to LanguageTopics] |