lib: improve examples in documentation
[nit.git] / lib / for_abuse.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # This file is free software, which comes along with NIT. This software is
4 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
5 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
6 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
7 # is kept unaltered, and a notification of the changes is added.
8 # You are allowed to redistribute it and sell it, alone or is a part of
9 # another product.
10
11 # Service management trough the `for` control structure.
12 #
13 # The module is a proof-of-concept to investigate the abuse of
14 # the `for` structure to implement various services.
15 #
16 # The idea is that, with a `for`, the service-provider can:
17 # * control the end of the service (thus can finalize things
18 # like releasing ressources)
19 # * communicate data with the user on each iteration; the used can
20 # also communicate results to the provider.
21 module for_abuse
22
23 # Encapsulation of service in a `for`-compatible interface.
24 #
25 # The service is not effectively started until the iterate method
26 # is called. Then, each step of the iteration is a step in the service.
27 #
28 # While, for a typing point of view, abusers are just collections,
29 # the point of this class is to tag services that return a ForAbuser
30 # object.
31 # Note that using abuser as genuine collection should work but is not
32 # recommended since it may cause mental health issues.
33 interface ForAbuser[E]
34 super Collection[E]
35 end
36
37 # Abuser to read a file, see `file_open`
38 private class ReadFileForAbuser
39 super ForAbuser[IFStream]
40 var path: String
41 redef fun iterator do return new ReadFileForAbuserIterator(path)
42 end
43
44 # Abuser iterator to read a file, see `file_open`
45 private class ReadFileForAbuserIterator
46 super Iterator[IFStream]
47 redef var item: IFStream
48 redef var is_ok = true
49 init(path: String)
50 do
51 # start of service is to open the file, and return in
52 item = new IFStream.open(path)
53 end
54 redef fun next
55 do
56 # end of service is to close the file
57 # there is only one iteration
58 is_ok = false
59 item.close
60 end
61 end
62
63 ####
64
65 # A comparison query.
66 # The user is asked to compare `a` with `b` then set `res` accordingly.
67 #
68 # * if `a < b` then the user sets `res` to -1
69 # * if `a > b` then the user sets `res` to 1
70 # * if `a == b` then the user sets `res` to 0
71 #
72 # It is the responsibility of the user to implement a total order.
73 # ie. the implemented comparison must be asymmetric, transitive and total.
74 class CompareQuery[E]
75 # The first element to compare
76 var a: E
77 # The second element to compare
78 var b: E
79 # The result of the comparison (according to the user)
80 var res writable = 0
81 end
82
83 # Abuser for sorting array, see `sort_fa`
84 private class SortAbuser[E]
85 super ForAbuser[CompareQuery[E]]
86 var array: Array[E]
87 redef fun iterator do return new SortAbuserIterator[E](array)
88 end
89
90 # Abuser iterator for sorting array, see `sort_fa`
91 # Implements a sort by permutation
92 private class SortAbuserIterator[E]
93 super Iterator[CompareQuery[E]]
94 # The index of the big loop
95 var i: Int
96 # The index of the small loop
97 var j: Int
98 # The array to sort
99 var array: Array[E]
100 # The query used to communicate with the user.
101 # For ecological concerns, a unique CompareQuery is instatiated.
102 var query: nullable CompareQuery[E]
103 redef fun item do return query.as(not null)
104 init(array: Array[E])
105 do
106 self.array = array
107 # Initialize the algorithm, see `next` for the rest
108 i = 0
109 j = 0
110 if not is_ok then return
111 query = new CompareQuery[E](array[i], array[j])
112 end
113 redef fun is_ok do return i < array.length - 1
114 redef fun next
115 do
116 # Process the last query
117 if item.res > 0 then
118 var tmp = array[i]
119 array[i] = array[j]
120 array[j] = tmp
121 end
122 # Get the next iteration
123 j += 1
124 if j >= array.length then
125 # End of small loop
126 i += 1
127 j = i + 1
128 end
129 if not is_ok then return
130 # Prepare the next query
131 item.a = array[i]
132 item.b = array[j]
133 item.res = 0
134 end
135 end
136
137 redef class Array[E]
138 # Sort an array trough a `for` abuse.
139 # The user uses the provided query (item) to implements its own comparison
140 #
141 # var a = [1, 3, 2]
142 # for q in a do q.res = q.a <=> q.b
143 # assert print a == 123
144 #
145 # Implements a sort by permutation.
146 fun sort_fa: ForAbuser[CompareQuery[E]]
147 do
148 return new SortAbuser[E](self)
149 end
150 end
151
152 ####
153
154 # Open and read a file trough a `for` abuse.
155 # The abuse just ensures that the file is closed after the reading.
156 #
157 # for f in file_open("/etc/issue") do
158 # print f.read_line
159 # end # f is automatically closed here
160 fun file_open(path: String): ForAbuser[IFStream]
161 do
162 return new ReadFileForAbuser(path)
163 end