manual: add nitish and avoid name conflicts
[nit.git] / doc / manual / variable.md
1 # Local Variables and Static Typing
2
3 `var` declares local variables. In fact there is no global variable in Nit, so in this document *variable* always refers to a local variable. A variable is visible up to the end of the current
4 control structure. Two variables with the same name cannot coexist: no nesting nor masking.
5
6 Variables are bound to values. A variable cannot be used unless it has a value in all control flow paths (à la Java).
7
8 ~~~
9 var exp = 10
10 # ...
11 var a
12 if exp > 0 then
13     a = 5
14 else
15     a = 7
16 end
17 print a # OK
18 ~~~
19
20 ~~~nitish
21 var b
22 if exp > 0 then
23     b = 6
24 end
25 print b # Compile error: y is possibly not initialized
26 ~~~
27
28 ## Adaptive Typing
29
30 Nit features adaptive typing, which means that the static type of a variable can change according to: the assignments of variables, the control flow, and some special operators (`and`, `or`,
31 `or else`, `==`, `!=`, and `isa`).
32
33 ~~~
34 var c # a variable
35 c = 5
36 # static type is Int
37 print c + 1 # outputs 6
38 c = [6, 7]
39 # static type is Array[Int]
40 print c[0] # outputs "6"
41 ~~~
42
43 ~~~
44 # ...
45 var d
46 if exp > 0 then
47     d = 5
48 else
49     d = 6
50 end
51 # Static type is Int
52 print d + 1
53 ~~~
54
55 ## Variable Upper Bound
56
57 An optional type information can be added to a variable declaration. This type is used as an upper bound of the type of the variable. When a initial value is given in a variable declaration without a specific type information, the static type of the initial value is used as an upper bound. If no type and no initial value are given, the upper bound is set to `nullable Object`.
58
59 ~~~nitish
60 var e: Int # Upper bound is Int
61 e = "Hello" # Compile error: expected Int
62
63 var f = 5 # Upper bound is Int
64 f = "Hello" # Compile error: expected Int
65 ~~~
66
67 ~~~
68 var g: Object # Upper bound is Object
69 g = 5 # OK since Int specializes Object
70
71 var h: Object = 5 # Upper bound is Object
72 h = "Hello" # OK
73 ~~~
74
75 The adaptive typing flow is straightforward, therefore loops (`for`, `while`, `loop`) have a special requirement: on entry, the upper bound is set to the current static type; on exit, the upper bound is reset to its previous value.
76
77 ~~~nitish
78 var l: Object
79 # static type is Object, upper bound is Object
80 l = 5
81 # static type is Int, bound remains Object
82 while l > 0 do
83     # static type remains Int, bound sets to Int
84     l -= 1 # OK
85     l = "Hello" # Compile error: expected Int
86 end
87 # static type is Int, bound reset to Object
88 l = "Hello" # OK
89 ~~~
90
91 ## Type Checks
92
93 `isa` tests if an object is an instance of a given type. If the expression used in an `isa` is a variable, then its static type is automatically adapted, therefore avoiding the need of a specific cast.
94
95 ~~~
96 var m: Object = 5
97 # ...
98 if m isa Int then
99     # static type of m is Int
100     print m * 10 # OK
101 end
102 ~~~
103
104 Remember that adaptive typing follows the control flow, including the Boolean operators.
105
106 ~~~
107 var n = new Array[Object]
108 n.add(1)
109 n.add(true)
110 n.add("one")
111 n.add(11)
112
113 for i in n do
114     # the static type of i is Object
115     if not i isa Int then continue
116     # now the static type of i is Int
117     print i * 10 # OK
118 end
119 ~~~
120
121 An interesting example:
122
123 ~~~
124 var max = 0
125 for i in n do
126     if i isa Int and i > max then max = i
127     # the > is valid since, in the right part
128     # of the "and", the static type of i is Int
129 end
130 print max # outputs 11
131 ~~~
132
133 Note that type adaptation occurs only in an `isa` if the target type is more specific that the current type.
134
135 ~~~
136 var col: Collection[Int] = [1, 2, 3]
137 if col isa Comparable then
138     # the static type is still Collection[Int]
139     # even if the dynamic type of a is a subclass
140     # of both Collection[Int] and Comparable
141     # ...
142 end
143 ~~~
144
145 ## Nullable Types
146
147 `null` is a literal value that is only accepted by some specific static types. However, thanks to adaptive typing, the static type management can be mainly automatic.
148
149 `nullable` annotates types that can accept `null` or an expression of a compatible nullable static type.
150
151 ~~~
152 var o: nullable Int
153 var p: Int
154 o = 1 # OK
155 p = 1 # OK
156 o = null # OK
157 o = p # OK
158 ~~~
159
160 ~~~nitish
161 p = null # Compile error
162 p = o # Compile error
163 ~~~
164
165 Adaptive typing works well with nullable types.
166
167 ~~~
168 var q
169 if exp > 0 then
170     q = 5
171 else
172     q = null
173 end
174 # The static type of q is nullable Int
175 ~~~
176
177 Moreover, like the `isa` keyword, the `==` and `!=` operators can adapt the static type of a variable when compared to `null`.
178
179 ~~~
180 var r: nullable Int = 10
181 # ...
182 if r != null then
183     # The static type of r is Int (without nullable)
184     print r + 6
185 end
186 # The static type of r is nullable Int
187 ~~~
188
189 And another example:
190
191 ~~~
192 var s: nullable Int = 10
193 # ...
194 loop
195     if s == null then break
196     # The static type of s is Int
197     print s + 1
198
199     s = null
200     # The static type of s is null
201 end
202 ~~~
203
204 `or else` can be used to compose a nullable expression with any other expression. The value of `x or else y` is `x` if `x` is not `null` and is `y` if `x` is null. The static type of `x or else y` is the combination of the type of `y` and the not null version of the type of `x`.
205
206 ~~~
207 var t: nullable Int = 10
208 # ...
209 var u = t or else 0
210 # the static type of u is Int (without nullable)
211 ~~~
212
213 Note that nullable types require a special management for [[attributes|attribute]] and [[constructors|constructor]].
214
215 ## Explicit Cast
216
217 `as` casts an expression to a type. The expression is either casted successfully or there is an `abort`.
218
219 ~~~
220 var v: Object = 5 # static type of v is Object
221 print v.as(Int) * 10 # outputs 50
222 ~~~
223
224 ~~~nitish
225 print v.as(String) # aborts: cast failed
226 ~~~
227
228 Note that `as` does not change the object nor does perform conversion.
229
230 ~~~
231 var w: Object = 5 # static type of w is Object
232 print w.as(Int) + 10 # outputs "15"
233 print w.to_s + "10" # outputs "510"
234 ~~~
235
236 Because of type adaptation, `as` is rarely used on variables. `isa` (sometime coupled with `assert`) is preferred.
237
238 ~~~
239 var x: Object = 5 # static type of x is Object
240 assert x isa Int
241 # static type of x is now Int
242 print x * 10 # outputs 50
243 ~~~
244
245 `as(not null)` can be used to cast an expression typed by a nullable type to its non nullable version. This form keeps the programmer from writing explicit static types.
246
247 ~~~
248 var y: nullable Int = 5 # static type of y is nullable Int
249 print y.as(not null) * 10 # cast, outputs 50
250 print y.as(Int) * 10 # same cast, outputs 50
251 assert y != null # same cast, but type of y is now Int
252 print y * 10 # outputs 50
253 ~~~
254
255 ## Static Type Combination Rule
256
257 Adaptive typing, literal arrays, and `or else` need to determine a static type by combining other static types. This is done by using the following rule:
258
259 -   The final type is `nullable` if at least one of the types is `nullable`.
260
261 -   The final type is the static type that is more general than all the other types.
262
263 -   If there is no such a type, and the thing typed is a variable, then the final type is the upper bound type of the variable; else there is a compilation error.
264
265 <!-- -->
266
267 ~~~
268 var dis: Discrete = 'a'
269 # Note: Int < Discrete < Object
270 var z
271 if exp > 0 then z = 1 else z = dis
272 # static type is Discrete
273 if exp < 0 then z = 1 else z = "1"
274 # static type is nullable Object (upper bound)
275 var a1 = [1, dis] # a1 is a Array[Discrete]
276 ~~~
277
278 ~~~nitish
279 var a2 = [1, "1"] # Compile error:
280         # incompatible types Int and String
281 ~~~