forked from carlfriess/eiffel-guide
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
744 lines (467 loc) · 29.9 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
<html>
<head>
<title>Eiffel Syntax Guide</title>
<link rel="stylesheet" type="text/css" href="Anders-font/styles.css">
<link href='https://fonts.googleapis.com/css?family=Lato:100|Open+Sans:300,600' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="prism.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="sidebar.js"></script>
<link rel="stylesheet" type="text/css" href="sidebar.css">
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body ng-app="sidebar">
<sidebar></sidebar>
<h1>A comprehensive guide to Eiffel syntax</h1>
<div class="divider"></div>
<h2>Introduction</h2>
<p>Welcome to this guide about the Eiffel programming language. It is designed to be a basic reference to help beginners get acquainted with the language. Some knowledge of other programming languages might be considered very useful. This should not be seen as a course or tutorial. Please help improve and maintain this page through <a href="https://github.com/carlfriess/eiffel-guide/">GitHub</a>. To get started, let's have a look at this simple hello world:</p>
<div class="code"><pre><code class="language-eiffel">
class
HELLO_WORLD
create
say_it
feature
say_it
do
Io.put_string ("Hello World!")
end
end
</code></pre></div>
<div class="output"><pre><code>Hello World!</code></pre></div>
<h2>Some basics</h2>
<p>The first difference you will notice in Eiffel compared to other languages like C++ or Java is the absence of curly brackets to separate code blocks. Instead in Eiffel we use keywords followed by <b>end</b>. We also do not ordinarily terminate lines of code with a semi-colon. However, it is acceptable to separate statements with a semi-colon if you so wish. Features (functions) are called without using brackets, if they do not accept any arguments (e.g. <b>target.my_function</b> instead of <b>target.my_function()</b>).
<h2>Naming_conventions</h2>
<p>In general, in Eiffel we use <b>snake_script</b> and not <b>CamelCase</b>.</p>
<p><b>CLASSES</b> should be spelled in capital letters.</p>
<p><b>features</b> (methods and attributes of classes) should be spelled small.</p>
<p><b>Objects</b> (instances of a class) should be capitalised.</p>
<h2>Features</h2>
<p>In Eiffel, the Methods and Attributes (Variables) of a class are called features. We can define them by using the keyword <b>feature</b> followed by the features name within a class. We specify the features type or return type by using a colon followed by the types name. If a feature is a function and takes arguments we can list them in brackets together with their types. The keyword <b>do</b> is used to denote where the code of the function starts, followed by <b>end</b> at the end.</p>
<div class="code"><pre><code class="language-eiffel">
class
BAKERY
feature
number_of_cakes : INTEGER
-- A variable containing an integer
name_of_my_favourite_cake : STRING
-- A variable containing a string
price_of_one_cake : REAL
-- A variable containing a floating point number
buy_cake (price : REAL; flavour : STRING) -- A function accepting arguments
do
-- Some code here...
end
is_cake_available : BOOLEAN -- A function returning true or false
do
Result := number_of_cakes > 0
end
end
</code></pre></div>
<p>The return value of a feature is set by assigning it to the <b>Result</b> variable. Unlike other languages, the return statement does not exist.</b>
<p>Also notice, that when defining a feature, arguments are separated using semi-colons. However, when calling the feature, they are separated by means of a comma.</p>
<p>Features may also use local variables which are internal to the function. However, they must be declared with their type before the <b>do</b> keyword using the <b>local</b> keyword. For example:</p>
<div class="code"><pre><code class="language-eiffel">
class
MY_CLASS
feature
my_feature
local
my_variable_1 : INTEGER
my_variable_2 : STRING
do
-- Some code here...
end
end
</code></pre></div>
<h2>Assigners</h2>
<p>The variables of a class are read-only to its clients. To change their values, we can use a setter, a feature that takes the new value as an argument, like in the case of <b>set_age</b> below:</p>
<div class="code"><pre><code class="language-eiffel">
class
PERSON
feature
age: INTEGER
set_age ( new_age: INTEGER )
do
age := new_age
end
end
</code></pre></div>
<p>So, a client of the class would not be able to change the age by using <b>Person.age := 21</b>, as <b>Person.age</b> is read-only for clients. Instead it would call <b>Person.set_age(21)</b>. However, if for some reasons you are feeling radical and want to use <b>Person.age := 21</b>, you can give age a so called assigner by using the <b>assign</b> keyword and specifying a setter.</p>
<div class="code"><pre><code class="language-eiffel">
class
PERSON
feature
age: INTEGER assign set_age
set_age ( new_age: INTEGER )
do
age := new_age
end
end
</code></pre></div>
<p>Now, <b>Person.age := 21</b> is simply a shortcut for <b>Person.set_age(21)</b>.</p>
<h2>Once-executed features</h2>
<p>Although quite rarely used, in Eiffel a feature can be specified to only be executed once then save its return value and simply return it immediately at every subsequent call. To do this, simply use the <b>once</b> keyword instead of <b>do</b>.</p>
<div class="code"><pre><code class="language-eiffel">
feature
first_name: STRING
last_name: STRING
full_name: STRING
once
first_name := "John"
last_name := "Doe"
Result := first_name + " " + last_name
end
</code></pre></div>
<p>This can be useful for initialisation. A setup feature could implement the initialisation of an object but be called from multiple other features. By using <b>once</b>, we can guarantee that it will only perform the initialisation once regardless of who calls it and how many times it is called.</b>
<p>It is also possible to specify in which context the feature should be considered as called. This is particularly important when using multiple threads or processes. For instance, you may want to execute a feature only once for each Process, once for each Thread or for every object instance. To specify this, use the once keys <b>"PROCESS"</b>, <b>"THREAD"</b> and <b>"OBJECT"</b>. These are specified as strings and in brackets after the <b>once</b> keyword like so: <b>once ("PROCESS")</b>. The default once key is <b>"THREAD"</b>.</p>
<h2>Classes</h2>
<p>The simplest way to define a class in Eiffel is just to name it and give it some features. It may even inherit features from other classes. For this we can list all of the desired classes after stating the <b>inherit</b> keyword. Using the <b>redefine</b> keyword features may be specified for classes that should be redefined in this class and not inherited.</p>
<div class="code"><pre><code class="language-eiffel">
class
MY_CLASS
inherit
SOME_OTHER_CLASS
redefine
some_inherited_feature
end
feature
some_feature
do
[...]
end
some_inherited_feature
[...]
end
</code></pre></div>
<p>When redefining a feature, it can be helpful to call its old version. So, within the redefinition, the keyword <b>Precursor</b> is set to the old version and calls can be made like this: <b>Precursor("Some argument")</b>. If you would like to use a version from a specific parent, you can add curly brackets: <b>Precursor { SOME_PARENT } ("Some argument")</b></p>
<p>In the case of <b>MY_CLASS</b>, when we want to create an instance of the class, we first need to define the object and specify its type. Then, we use the <b>create</b> keyword to initialise the object, before making other calls to it. A client of the class might look like this:</p>
<div class="code"><pre><code class="language-eiffel">
feature
example
local
New_object: MY_CLASS
do
create New_object
New_object.some_feature
end
</code></pre></div>
<h2>Reference vs. Expanded Classes</h2>
<p>In Eiffel there is a key differentiation between reference and expanded classes. By default a class is of the reference type. To declare a class as expanded, we use the <b>expanded</b> keyword before <b>class</b>.</p>
<p>As the name would suggest a reference class sets itself apart in that its attributes are references to other objects, either of classes defined by the developer or built-in classes such as <b>STRING</b> or <b>REAL</b>. As such, an object of a the reference type does not contain any actual values apart from addresses. It only contains references to where the values are stored in the memory. In C or C++ references would be referred to as pointers. An expanded class on the other hand does not contain references, but the actual values. This key difference has an effect on how we create and use classes.</p>
<p>Another difference, is that when used as an argument, data of an expanded type is passed by value, while data of reference types are passed by reference, since the object consists of addresses.</p>
<h3>Reference Classes</h3>
<p>When we define an object of a certain class, the computer will allocate memory to hold that class's attributes. However, in the case of a reference class, this allocated memory will only hold the references or addresses to the objects containing the actual values. So by default all attributes of a class will be set to <b>Void</b>, as the objects that the class refers to, do not exist yet. To create these we must always call <b>create</b> before using a new instance.</p>
<p>It is possible to test if an object <b>x</b> has been initialised yet by using the expression <b>x = Void</b>.</p>
<p>It is good style to use constructors to initialise attributes to the correct values and ensure that any class invariants are fulfilled. To enforce the use of constructors, we can specify features as possible constructors using the <b>create</b> keyword like so:</p>
<div class="code"><pre><code class="language-eiffel">
class
MY_CLASS
create
my_feature
feature
my_feature (some_argument : STRING)
do
-- Do something here...
end
end
</code></pre></div>
<p>An instance <b>my_object</b> of the class would then be initialised like so:</p>
<div class="code"><pre><code class="language-eiffel">
create my_object.my_feature("Hello World!")
</code></pre></div>
<p>You may specify as many constructors as you want. However, as soon as at least one constructor has been specified, a constructor must be used when creating a new instance. If no constructors are specified, then simply creating an object without adding a constructor will invoke <b>default_create</b>, which is a feature that is automatically added to every class without constructors and by default does nothing.</p>
<h3>Expanded Classes</h3>
<p>Expanded classes differ from reference classes in that they do not contain references, but rather the actual values of their attributes. For this reason, we do not need to call <b>create</b> before using objects that are instances of the class. All attributes are automatically set to their default initial values when the object is defined.</p>
<p>If <b>a</b> and <b>b</b> are both instances of an expanded class, <b>a := b</b> will copy all of <b>b</b> (including its values) into <b>a</b> and create a new instance with the same values.</p>
<p>On the other hand, if <b>a</b> and <b>b</b> are both instances of a reference class, then <b>a := b</b> will copy the reference to the instance of the class represented by <b>b</b> into <b>a</b>. In other words, now <b>a</b> and <b>b</b> will reference the same instance and any change to <b>a</b> will be reflected in <b>b</b>.</p>
<h2>Exporting features</h2>
<p>By default all features defined in a class will be available to clients of the class. To prevent this, we can use <b>{NONE}</b> to keep features internal and inaccessible to clients. The <b>Current</b> keyword is considered a client. Hence, when using <b>{NONE}</b> for a feature, it will not be accessible using <b>Current</b>. This is similar to using private in Java for instance.</p>
<p>In fact, in Eiffel we can be very specific about which features are available to <i>which</i> clients, by specifying the class a client must have in order to access the feature. For this we once again use the curly brackets and list all the desired classes like so:</p>
<div class="code"><pre><code class="language-eiffel">
class
A
feature -- `s` will be available to all clients of the class.
s
...
feature {NONE} -- `u` and `v` will only be available internally.
u, v
...
feature {A, B} -- `x` will only be available to clients of the same type
x -- and to clients of the type `B`.
...
feature {C} -- `y` and `z` will be available only to clients of the type C.
y, z
...
end
</code></pre></div>
<p>One more thing to consider is, that creation procedures are not considered qualified calls. Therefore, when using a feature as a constructor, where it is exported to does not apply. if you would like to still specify which features are available to which classes, you can use the same notation, but with the <b>create</b> declaration.</p>
<h2>Deferred Classes</h2>
<p>Above we had a look at how classes can inherit and export features. Deferred classes have the capability to specify features without defining them, so that children of the class must themselves define them.</p>
<p>As soon as a class contains at least one deferred feature, it must be declared as deferred (notice the <b>deferred</b> keyword before <b>class</b>). A feature can be declared as deferred by using the <b>deferred</b> keyword, followed immediately by the <b>end</b> statement. A deferred feature does not have to be declared as redefined in a child class.</p>
<div class="code"><pre><code class="language-eiffel">
deferred class
MY_CLASS
feature
some_feature: STRING
another_feature
deferred
end
end
</code></pre></div>
<h2>Aliases</h2>
<p>When using a custom class to store data, it can be useful to use operators in order to compare objects of that class. For this we must define a feature that performs the comparison and is an alias for an operator. We use the <b>alias</b> keyword after the feature name to choose the operator. In this example, people will be compared according to their age:</p>
<div class="code"><pre><code class="language-eiffel">
class
PERSON
feature
name: STRING
age: INTEGER
older_than alias ">" (other: PERSON) : BOOLEAN
do
Result := (age > other.age)
end
end
</code></pre></div>
<p>If we now had an instance of the class called <b>Joe</b> with the age 36 and another called <b>Tom</b> with the age 24, then <b>Joe > Tom</b> is true, while <b>Tom > Joe</b> is false.</p>
<h2>Multiple Inheritance</h2>
<p>We have already seen, that classes can inherit features from other classes and redefine them to change their behaviour. We have also seen that classes may defer features to be implemented in a child class. However, when inheriting from multiple classes we run into another problem: clashes.</p>
<p>If a class <b>C</b> inherits from two classes <b>A</b> and <b>B</b>, which both have a feature called <b>f</b> then we will need to rename or undefine the feature for at least one of the two classes. For this we can use the <b>rename</b> and <b>undefine</b> keywords similarly to <b>redefine</b>. Consider the following implementation of the before mentioned problem:</p>
<div class="code"><pre><code class="language-eiffel">
class
A
feature
f
do
-- Some code...
end
g
do
-- Some code...
end
end
</code></pre></div>
<div class="code"><pre><code class="language-eiffel">
class
B
feature
f
do
-- Some different code...
end
g
do
-- Some different code...
end
end
</code></pre></div>
<div class="code"><pre><code class="language-eiffel">
class
C
inherit
A
rename
f as A_f -- The feature f inherited from A is now called A_f within C
end
B
undefine
g -- The feature g inherited from B is no longer part of C
end
feature
...
end
</code></pre></div>
<p>In the above example, the feature <b>f</b> inherited from <b>B</b> is still called <b>f</b> in <b>C</b>, the same goes for the feature <b>g</b> inherited from <b>A</b>. So in conclusion, the class <b>C</b> now has the features <b>A_f</b> (inherited from A), <b>f</b> (inherited from B) and <b>g</b> (inherited from A).</p>
<p>If the classes <b>A</b> and <b>B</b> were inheriting the features <b>f</b> and <b>g</b> from the same class instead of defining them themselves, then in fact there is no need to undefine or rename any of the features, as there is only one effective implementation for them.
<h2>Some basic I/O</h2>
<p>These are some examples of basic input/output functions, that can be used to interact with a user at a command line level:</p>
<p><b>Io.put_string ("Hello World!")</b> Prints out a string</p>
<p><b>Io.put_integer (42)</b> Prints out an integer</p>
<p><b>Io.put_real (9.99)</b> Prints out a real</p>
<p><b>Io.put_boolean (true)</b> Prints out a true or false</p>
<p><b>Io.new_line</b> Prints out a new line</p>
<p><b>Io.read_line</b> Reads in one line of users input and stores it in <b>Io.last_string</b></p>
<p><b>Io.read_integer</b> Reads in an integer from users input and stores it in <b>Io.last_integer</b></p>
<h2>Operators</h2>
<p><b>:=</b> Assignment operator. Ex: <b>meaning_of_life := 42</b></p>
<p><b>=</b> Equality operator (== in many other languages). Ex: <b>1 + 2 = 3</b> would be true</p>
<p><b>/=</b> Inequality operator (!= in many other languages). Ex: <b>meaning_of_life /= 42</b></p>
<p><b><</b>, <b>></b>, <b><=</b>, <b>>=</b> Comparison operators.</p>
<p><b>+</b>, <b>-</b>, <b>*</b>, <b>/</b> Mathematical operators.</p>
<p><b>//</b> Integer division operator. Ex: <b>5/2=2.5</b> vs <b>5//2=2</b></p>
<p><b>\\</b> Modulo. Ex: <b>5\\2=1</b></p>
<p><b>equal (x, y)</b> To compare strings we can use the equal function.</p>
<p><b>Current</b> Though not an operator, this always references the currently executing instance of a class.</p>
<p><b>|..|</b> Describes an integer interval. Useful in loops. e.g. <b>1 |..| 5</b></p>
<p><b>..</b> Describes an interval of integers or characters in inspect constructions. e.g. <b>a .. z</b></p>
<p><b>and</b>, <b>or</b>, <b>xor</b>, <b>not</b> Logic operators.</p>
<p><b>and then</b>, <b>or else</b>, <b>implies</b> Semistrict logic operators (evaluation stops when the result is known).</p>
<h2>Control Structures</h2>
<p>In Eiffel the syntax for an if else structure is as follows (notice, there are no brackets):</p>
<div class="code"><pre><code class="language-eiffel">
if meaning_of_life = 42
then
-- code if true
else
-- code if false
end
</code></pre></div>
<p>Eiffel also provides switch-like Statements called <b>inspect</b>, where a variable is compared to various values. The else condition is the default condition that applies when no case matches the input.</p>
<div class="code"><pre><code class="language-eiffel">
inspect input_integer
when 2 then
-- Code when input_integer equals 2
when 3, 5 then
-- Code when input_integer equals 3 or 5
when 7..9 then
-- Code when input_integer equals 7 or 8 or 9
else
-- Code when input_integer does not equal 2, 3, 5, 7, 8 nor 9
end
</code></pre></div>
<p>Unlike switch statements in other languages, in Eiffel the code following a matching case is not evaluated and there is no break statement in Eiffel.</p>
<h2>Loops</h2>
<p>This is the typical syntax for a simplified from loop (comparable to for loops in other languages):</p>
<div class="code"><pre><code class="language-eiffel">
from
i := 0
until
i >= 10
loop
-- do something
i := i + 1
end
</code></pre></div>
<p>Notice, that in Eiffel loops are evaluated <i>until</i> the conditional becomes true rather than <i>while</i> the conditional is true, which is common in most other languages (Ex. for-loop in C, Java, etc.).</p>
<p>It is also possible to add contracts to a from loop. The two options here are to specify a <b>variant</b> expression and an <b>invariant</b> expression. The variant must decrease by at least 1 after each cycle of the loop, while the invariant remains the same. Here is an example:</p>
<div class="code"><pre><code class="language-eiffel">
from
i := 0
n := 10
invariant
n > 0
until
i >= 10
loop
i := i + 1
variant
n-i
end
</code></pre></div>
<p>The contracts in loops are designed to prevent bugs such as endless loops. As such the variant is supposed to be an estimation of the number of iterations.
<p>There also exists an "across"-loop, which goes through an iterable object (such as a list), and creates a cursor. Make sure that the object is in fact iterable. For this all elements must have a feature called <b>next</b> and the iterated object should have the features <b>first</b> and <b>last</b>. The cursor points to the next element of the iterated object at each execution of the loop. Since it is a cursor, you must access the actual elements by using <b>my_cursor.item</b>.</p>
<div class="code"><pre><code class="language-eiffel">
across list_of_customers as customer loop
Io.put_string (customer.item.name)
Io.new_line
end
</code></pre></div>
<p>For instance, an integer interval is an iterable object.</p>
<div class="code"><pre><code class="language-eiffel">
across 1 |..| 5 as it loop
Io.put_integer (it.item)
Io.new_line
end
</code></pre></div>
<h2>Contracts</h2>
<p>Contracts are a concept used in Eiffel to avoid bugs. Although these should be disabled in a production runtime, during development they can be quite useful. There are three types of assurance elements: preconditions (used in features), postconditions (used in features) and class invariants.</p>
<p>Preconditions are defined using the <b>require</b> keyword. They should contain a tag and a boolean expression. Postconditions are written the same way, but we use the <b>ensure</b> keyword. We can use the <b>old</b> notation to compare a variable's value to its value before the feature was executed. Here is an example that might be used in the <b>BAKERY</b> class we saw above:</p>
<div class="code"><pre><code class="language-eiffel">
number_of_available_cakes : INTEGER
buy_cakes (amount : INTEGER)
require
positive_amount: amount > 0 -- Check that amount is a positive number
do
number_of_available_cakes = number_of_available_cakes - amount
ensure
amount_reduced: number_of_available_cakes = old number_of_available_cakes - amount
-- Check that the number of available cakes has decreased correctly
end
</code></pre></div>
<p>Class invariants are checked every time an operation is performed on the class, such as calling a feature. We declare class invariants using the <b>invariant</b> keyword. In this example we will check that a variable is always positive:</p>
<div class="code"><pre><code class="language-eiffel">
class
MY_CLASS
feature
some_number : INTEGER
some_feature
do
-- Some code here...
end
invariant
positive: some_number > 0
end
</code></pre></div>
<h2>Genericity</h2>
<p>This is a concept that is particularly useful when creating structures like lists. Using genericity we can define classes with generic types that can be specified later. Like this we can use the same class to make a list of strings and to make a list of integers for instance.</p>
<p>To use this in a class, the we can specify a generic parameter (ex. <b>G</b>) in in square brackets after the class name like so <b>class MY_CLASS [G]</b>. Then when defining an object of this class er must specify which class to use for the generic type like this: <b>my_object: MY_CLASS[ STRING ]</b>. This is a more detailed example of a generic class:</p>
<div class="code"><pre><code class="language-eiffel">
class MY_LIST [G] feature
first : G
last : G
extend (new_element: G)
do
-- Add element to list...
end
end
</code></pre></div>
<div class="code"><pre><code class="language-eiffel">
class SCHOOL feature
list_of_students : MY_LIST[ STUDENT ]
list_of_classes : MY_LIST[ MY_LIST[ STUDENT ] ]
end
</code></pre></div>
<h2>Agents</h2>
<p>Particularly in event-driven programming, it can be useful to represent a feature using an object. For this we can use agents. We create an agent by using the <b>agent</b> keyword followed by the features we want to pass. To call the feature encapsulated by an agent object we use <b>my_agent.call()</b> if we expect no return value. To receive a return value we use <b>my_agent.item()</b> instead.</p>
<p>The following example is similar to a situation that might occur when programming a GUI. When run, the application prints "<i>The button was clicked!</i>".</p>
<div class="code"><pre><code class="language-eiffel">
class
APPLICATION
create
run
feature
run
local
button : BUTTON
do
create button.set_click_handler( agent click_event )
button.click
end
click_event
do
Io.put_string ("The button was clicked!")
end
end
</code></pre></div>
<div class="code"><pre><code class="language-eiffel">
class
BUTTON
create
set_click_handler
feature
click_handler : PROCEDURE [APPLICATION, TUPLE[]]
set_click_handler ( handler: PROCEDURE [APPLICATION, TUPLE[]] )
do
click_handler := handler
end
click
do
click_handler.call
end
end
</code></pre></div>
<p>To pass arguments to the feature when calling it through an agent we pass a tuple (denoted by square brackets) with all the arguments when invoking the agent. For this to work, we must also change the creation of the agent. To pass three arguments, we would create the agent using <b>my_agent := agent my_feature(?, ?, ?)</b> and then call it with <b>a.call([argument_1, argument_2, argument_3])</b>.</p>
<p>The type of an <b>my_agent</b> from above would be <b>PROCEDURE[ T, TUPLE[ ARG1, ARG2, ARG3 ] ]</b>, where <b>T</b> is the class <b>my_feature</b> belongs to and <b>ARG1</b>, <b>ARG2</b> and <b>ARG3</b> are the types of <b>argument_1</b>, <b>argument_2</b> and <b>argument_3</b> respectively.</p>
<p>If the encapsulated feature is to return a value, then the type is actually <b>FUNCTION[ T, TUPLE[ ARG1, ARG2, ARG3 ], RETURN_TYPE ]</b>.</p>
<h2>Garbage collection</h2>
<p>Eiffel uses a garbage collector which automatically removes any objects from the memory when they are no longer referenced anywhere. So unlike in C or C++ for instance, it is not necessary to manage the memory.</p>
<div class="divider" style="margin-top: 150px;"></div>
<div class="footer">Created by <a href="http://carlfriess.com/" target="_blank">Carl Friess</a> in 2015. <a href="https://github.com/carlfriess/eiffel-guide/graphs/contributors" target="_blank">Contributors</a> to the <a href="https://github.com/carlfriess/eiffel-guide/" target="_blank">GitHub Repo</a></div>
<!--
Github Corner by Tim Holman
http://tholman.com/github-corners/
-->
<a href="https://github.com/carlfriess/eiffel-guide" target="_blank" class="github-corner" aria-label="View source on Github"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#FFF; color:#263238; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
<script type="text/javascript">Array.prototype.slice.call(document.getElementsByTagName("code")).forEach(function(i){i.innerHTML=i.innerHTML.replace(/^\s+|\s+$/g,'');});</script>
<script type="text/javascript" src="prism.js"></script>
</body>
</html>