manual: fix examples to be nitunitables
[nit.git] / doc / manual / constructor.md
1 # Constructors
2
3 Constructors in Nit behave differently.
4
5 Their objective is double :
6
7 * be compatible with full multiple-inheritance
8 * be simple enough to be KISS and compatible with the principle of least surprise.
9
10
11 ## `new` construction and simple classes
12
13 Classes in OO models are often a simple aggregates of attributes and methods.
14
15 By default, the `new` construction require a value for each attribute defined in a class without a default value.
16
17 ~~~
18 class Product
19         var id: String
20         var description: String
21         var price: Float
22 end
23 var p = new Product("ABC", "Bla bla", 15.95)
24 assert p.id == "ABC"
25 ~~~
26
27 In subclasses, additional attributes are automatically collected.
28
29 ~~~
30 class Product
31         var id: String
32         var description: String
33         var price: Float
34 end
35 class Book
36         super Product
37         var author: String
38 end
39
40 var book = new Book("ABC", "Bla bla", 15.95, "John Doe")
41 ~~~
42
43
44 ## special `init` method
45
46 The special init method is automatically invoked after the end of a `new` construction.
47 It is used to perform additional systematic tasks.
48
49 Because the `init` is run at the end of the initialization sequence, initialized attributes are usable in the body.
50
51 ~~~
52 class Product
53         var id: String
54         var description: String
55         var price: Float
56 end
57 class OverpricedProduct
58         super Product
59         init
60         do
61                 price = price * 10.0
62         end
63 end
64 var op = new OverpricedProduct("ABC", "Bla bla", 15.95)
65 assert op.price.is_approx(159.50, 0.001)
66 ~~~
67
68
69 ## Uncollected attributes
70
71 There is three cases for an attributes to not be collected in the `new`.
72
73 * Attributes with a default value
74 * Attributes with the annotation `noinit`
75 * Attributes introduced in refinement of classes
76
77 ~~~
78 class Product
79         var id: String
80         var description: String
81         var price: Float
82 end
83 class TaxedProduct
84         super Product
85         var tax_rate = 9.90
86         var total_price: Float is noinit
87         init
88         do
89                 total_price = price * (1.0 + tax_rate/100.0)
90         end
91 end
92 var tp = new TaxedProduct("ABC", "Bla bla", 15.95)
93 assert tp.total_price.is_approx(17.52905, 0.00001)
94 ~~~
95
96 Note: The orchestration here is important. In order, the following is executed:
97
98 1. All defauts values are computed and set
99 2. Setters are invoked.
100 3. `init` is invoked.
101
102 Therefore, `total_price` cannot be initialised with a default value, because at the time of the computation of the default values, the attribute `price` in not yet initialised.
103
104
105 ## Generalized initializers
106
107 Initializers are methods that are automatically invoked by the new.
108 In fact, by default, the setter of an attribute is used as a initializer.
109
110 `autoinit` is used to register a method as a setter.
111
112 ~~~
113 class Product
114         var id: String
115         var description: String
116         var price: Float
117 end
118 class FooProduct
119         super Product
120         fun set_xy(x, y: Int) is autoinit do z = x * 10 + y
121         var z: Int is noinit
122 end
123 var fp = new FooProduct("ABC", "Bla bla", 15.96, 1, 3)
124 assert fp.z == 13
125 ~~~
126
127 Generalized setters are a powerful tool but often needed in only rare specific cases.
128 In most case, there is no reason that an argument of a `new` construction is not stored in the object as a real attribute.
129
130
131 ## Inheritance
132
133 As explained above, one of the main advantage of these constructors is their compatibility with multiple inheritance.
134
135 ~~~
136 class Product
137         var id: String
138         var description: String
139         var price: Float
140 end
141 class OverpricedProduct
142         super Product
143         init
144         do
145                 price = price * 10.0
146         end
147 end
148 class TaxedProduct
149         super Product
150         var tax_rate = 9.90
151         var total_price: Float is noinit
152         init
153         do
154                 total_price = price * (1.0 + tax_rate/100.0)
155         end
156 end
157 class FooProduct
158         super Product
159         fun set_xy(x, y: Int) is autoinit do z = x * 10 + y
160         var z: Int is noinit
161 end
162 class MultiProduct
163         super OverpricedProduct
164         super TaxedProduct
165         super FooProduct
166 end
167 var mp = new MultiProduct("ABC", "Bla bla", 15.96, 1, 3)
168 assert mp.id == "ABC"
169 assert mp.price == 159.6
170 assert mp.total_price == 175.4
171 assert mp.z == 13
172 ~~~
173
174
175 ## Named init
176
177 Named `init` are less flexible trough inheritance, thus should no be used.
178 They allow to have additional constructor for classes and more control in the construction mechanism.
179
180 ~~~
181 class Point
182         var x: Float
183         var y: Float
184
185         init origin
186         do
187                 init(0.0, 0.0)
188         end
189
190         init polar(r, phi: Float)
191         do
192                 var x = r * phi.cos
193                 var y = r * phi.sin
194                 init(x, y)
195         end
196
197         redef fun to_s do return "({x},{y})"
198 end
199 var p1 = new Point(1.0, 2.0)
200 assert p1.to_s ==  "(1,2)"
201 var p2 = new Point.origin
202 assert p2.to_s ==  "(0,0)"
203 var p3 = new Point.polar(1.0, 2.0)
204 assert p3.to_s ==  "(-0.4161,0.9092)"
205 ~~~
206
207
208 ## Legacy `init`
209
210 nameless `init` defined with argument or with an explicit visibility are still accepted as a fallback of the old-constructors.
211 They should not be used since they will be removed in a near future.
212
213
214 ## `new` factories
215
216 `new` factories permit to completely shortcut the class instantiation mechanim.
217 It could be used to provide `new` syntax on non-concrete class (mainly `extern class`).
218
219 `new` factories behave like a top-level function that return the result of the construction.
220 It is basically some kind of syntactic sugar.
221
222 ~~~
223 abstract class Person
224         var age: Int
225         new(age: Int)
226         do
227                 if age >= 18 then
228                         return new Adult(age)
229                 else
230                         return new Child(age)
231                 end
232         end
233 end
234 class Adult
235         super Person
236         # ...
237 end
238 class Child
239         super Person
240         # ...
241 end
242 ~~~