doc/manual: put back the manual in the main repository
[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 Book
31         super Product
32         var author: String
33 end
34
35 var book = new Book("ABC", "Bla bla", 15.95, "John Doe")
36 ~~~
37
38
39 ## special `init` method
40
41 The special init method is automatically invoked after the end of a `new` construction.
42 It is used to perform additional systematic tasks.
43
44 Because the `init` is run at the end of the initialization sequence, initialized attributes are usable in the body.
45
46 ~~~
47 class OverpricedProduct
48         super Product
49         init
50         do
51                 price = price * 10.0
52         end
53 end
54 var op = new OverpricedProduct("ABC", "Bla bla", 15.95)
55 assert op.price == 159.50
56 ~~~
57
58
59 ## Uncollected attributes
60
61 There is three cases for an attributes to not be collected in the `new`.
62
63 * Attributes with a default value
64 * Attributes with the annotation `noinit`
65 * Attributes introduced in refinement of classes
66
67 ~~~
68 class TaxedProduct
69         super Product
70         var tax_rate = 9.90
71         var total_price: Float is noinit
72         init
73         do
74                 total_price = price * (1.0 + tax_rate/100.0)
75         end
76 end
77 var tp = new TaxedProduct("ABC", "Bla bla", 15.95)
78 assert tp.total_price == 17.52905
79 ~~~
80
81 Note: The orchestration here is important. In order, the following is executed:
82
83 1. All defauts values are computed and set
84 2. Setters are invoked.
85 3. `init` is invoked.
86
87 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.
88
89
90 ## Generalized initializers
91
92 Initializers are methods that are automatically invoked by the new.
93 In fact, by default, the setter of an attribute is used as a initializer.
94
95 `autoinit` is used to register a method as a setter.
96
97 ~~~
98 class FooProduct
99         super Product
100         fun set_xy(x, y: Int) is autoinit do z = x * 10 + y
101         var z: Int is noinit
102 end
103 var fp = new FooProduct("ABC", "Bla bla", 15.96, 1, 3)
104 assert fp.z == 13
105 ~~~
106
107 Generalized setters are a powerful tool but often needed in only rare specific cases.
108 In most case, there is no reason that an argument of a `new` construction is not stored in the object as a real attribute.
109
110
111 ## Inheritance
112
113 As explained above, one of the main advantage of these constructors is their compatibility with multiple inheritance.
114
115 ~~~
116 class MultiProduct
117         super OverpricedProduct
118         super TaxedProduct
119         super FooProduct
120 end
121 var mp = new MultiProduct("ABC", "Bla bla", 15.96, 1, 3)
122 assert mp.id == "ABC"
123 assert mp.price == 159.6
124 assert mp.total_price == 175.4
125 assert mp.z == 13
126 ~~~
127
128
129 ## Named init
130
131 Named `init` are less flexible trough inheritance, thus should no be used.
132 They allow to have additional constructor for classes and more control in the construction mechanism.
133
134 ~~~
135 class Point
136         var x: Float
137         var y: Float
138
139         init origin
140         do
141                 init(0.0, 0.0)
142         end
143
144         init polar(r, phi: Float)
145         do
146                 var x = r * phi.cos
147                 var y = r * phi.sin
148                 init(x, y)
149         end
150
151         redef fun to_s do return "({x},{y})"
152 end
153 var p1 = new Point(1.0, 2.0)
154 assert p1.to_s ==  "(1,2)"
155 var p2 = new Point.origin
156 assert p2.to_s ==  "(0,0)"
157 var p3 = new Point.polar(1.0, 2.0)
158 assert p3.to_s ==  "(-0.4161,0.9092)"
159 ~~~
160
161
162 ## Legacy `init`
163
164 nameless `init` defined with argument or with an explicit visibility are still accepted as a fallback of the old-constructors.
165 They should not be used since they will be removed in a near future.
166
167
168 ## `new` factories
169
170 `new` factories permit to completely shortcut the class instantiation mechanim.
171 It could be used to provide `new` syntax on non-concrete class (mainly `extern class`).
172
173 `new` factories behave like a top-level function that return the result of the construction.
174 It is basically some kind of syntactic sugar.
175
176 ~~~
177 abstract class Person
178         var age: Int
179         new(age: Int)
180         do
181                 if age >= 18 then
182                         return new Adult(age)
183                 else
184                         return new Child(age)
185                 end
186         end
187 end
188 class Adult
189         super Person
190         # ...
191 end
192 class Child
193         super Person
194         # ...
195 end
196 ~~~