Skip to content
This repository
Browse code

[doc] CONTRIBUTING: merged stdlib guidelines

  • Loading branch information...
commit f5b2865705e5a4027b3fa0a52ded34a677bdb349 1 parent fb77bd1
Frederic Ye authored October 03, 2012
243  CONTRIBUTING.md
Source Rendered
@@ -37,6 +37,249 @@ YEAR.MONTH.DAY, Version SEMVER (stability), GIT_HASH
37 37
 
38 38
 * change 3
39 39
 
  40
+# Stdlib
  41
+
  42
+## How to write an Opa module
  43
+
  44
+Read this before writing an Opa module.
  45
+If you don't, chances are that the module will not be kept.
  46
+
  47
+The role of these guidelines is to make sure that:
  48
+
  49
+- we can find our way in the code easily
  50
+- we produce documentation for end-users
  51
+- your changes break neither the compiler nor the user's code.
  52
+
  53
+### I. All code must be documented.
  54
+
  55
+For examples of documented code, see the existing code.
  56
+Try to stay as much as possible is the same spirit, and
  57
+check that the generated html (opadoc) is well formed.
  58
+
  59
+Documenting takes only a few minutes.
  60
+Understanding undocumented code takes hours or days.
  61
+If you don't document your code, someone will hate you passionately.
  62
+You have been warned.
  63
+
  64
+Important Note: Don't confuse "commenting" and "documenting".
  65
+Comments are good but can't replace documentation.
  66
+Again, see the examples.
  67
+
  68
+Documentation MUST indicate, among other things
  69
+- what the module is for
  70
+- who it is for ("@audience PUBLIC"/"@audience PRIVATE"/...)
  71
+- possibly, how it is used, by who, in particular for modules of stdlib.core,
  72
+because any change in this kind of modules can have an impact on the compiler.
  73
+
  74
+For an example of documentation, see DOCUMENTING, in this directory,
  75
+or see all the existing documentation.
  76
+
  77
+### II. How should I call my module? Where should I put it?
  78
+
  79
+We have a notion of packages. The compiler is fully separated with respect to
  80
+packages.
  81
+
  82
+The main criterium for the separation of files is the packages dependencies.
  83
+
  84
+Package names can be named with a '.' (dot), but it is a fake hierarchy.  In
  85
+fact, a dot can be seen like an underscore, and packages are identifying by
  86
+their names, so, if it is not needed, do not go too deep in the hierarchy.
  87
+
  88
+#### II.1) stdlib.core
  89
+
  90
+If your module is used by the compiler, it must go to : stdlib.core
  91
+This package is needed for core Opa features, it contains mostly run time
  92
+support, like comparison, serialization, servers codes.
  93
+
  94
+This package also defines its own interface for the compiler, i.e. the complete
  95
+set of function the compiler can insert calls on. This interface is declared by declaration tagged by @opacapi directives.
  96
+Theses declarations should only be toplevel aliases, on functions in stdlib.core,
  97
+and the name of each alias must be the full path of the function with dots
  98
+replaced by underscores.
  99
+E.g. : Value_serialize = Value.serialize
  100
+
  101
+Be extremly aware of the fact that we are trying to reduce as much as possible
  102
+the size of the minimal server. This has also an important impact on the debugging.
  103
+If your module is not used by the compiler, then, it has really nothing to do in stdlib.core.
  104
+If you add a lot of code in stdlib.core, someone will hate you passionately.
  105
+You have been warned.
  106
+
  107
+##### II.2) stdlib.*
  108
+
  109
+These packages are additionnaly libs we want to be part of the standard library.
  110
+It is still not really clear if a package should be in the stdlib, or not.
  111
+Probably most of generic packages developped @mlstate will be in stdlib.*
  112
+
  113
+If your package is too specific, then it is probably better to make a separate package.
  114
+
  115
+some example:
  116
+  facebook -> not is stdlib, TODO: specify the package organisation.
  117
+  fgraph -> stdlib.fgraph
  118
+
  119
+If you want to add several modules related to the same thing, it would be preferable
  120
+to create a new package. (cf e.g. fgraph)
  121
+If your module is an extension of an existing package, simply add it in the corresponding package.
  122
+
  123
+### III. Code goes into modules.
  124
+
  125
+Remember, by default, in Opa, everything sits in the current package namespace.
  126
+Every typename and every value name you create therefore pollutes the current package namespace,
  127
+potentially breaking someone else's code.
  128
+
  129
+Consequently, all your values must be in modules, and/or restricting the interfaces
  130
+with the scopes directives :
  131
+`@public`
  132
+`@package`
  133
+`@private`
  134
+
  135
+Similarly, all your types should respect the namespace conventions.
  136
+For the moment, we don't have a syntax to put types into record.
  137
+Until then, if you wish to add a type "foo" to your module "Foo", call it "Foo.foo".
  138
+The name of types should strictly follow the hierarchy of modules.
  139
+
  140
+If you wish to add a function or a type to the global namespace, ask the Opa team first.
  141
+Be aware that big changes in the stdlib are dangerous because of the number of potential
  142
+users which already use it.
  143
+Be aware that if you add a function with a ugly name (or even worth, a function with a
  144
+name incoherent with the implementation), someone could use it the next day,
  145
+and if you want to change some names, and types after that, it will imply a big refactoring
  146
+everywhere your functions are used.
  147
+
  148
+If you add function which does not follow naming conventions, or argument order conventions,
  149
+or any other conventions written in this file, someone will hate you passionately.
  150
+You have been warned.
  151
+
  152
+Remember that once a Opa distribution will be done, we will no more be able to change any interfaces !
  153
+There is no hurry. Take your time. Review your code, ask advice for names of functions to other people,
  154
+it is always good to have several point of vues.
  155
+See also if a correspond lib does not already exists in an other language.
  156
+For exemple, if there is a reference API in an other language, you can keep the same names
  157
+(convention used e.g. in fgraph, the API is mostly preserved from OcamlGraph)
  158
+
  159
+Let's say we are playing in a contest of beauty of API.
  160
+
  161
+### IV. Naming conventions.
  162
+
  163
+values_look_like_this
  164
+ModuleLookLikeThis
  165
+TypesInModule.Look.like_this
  166
+fields_look_like_this
  167
+files_look_like_this.opa
  168
+
  169
+Accessor functions:
  170
+
  171
+get_foo
  172
+is_foo
  173
+
  174
+Conversion functions:
  175
+
  176
+Foo.of_bar
  177
+Foo.to_bar
  178
+
  179
+### IV. Types are closed.
  180
+
  181
+When you define a new type or data structure, chances are that users don't need
  182
+to know how it's implemented, so you should make it @abstract (if users should
  183
+see the type but not its definition) or @private (if the type is purely
  184
+internal). This will make error messages simpler for the user and it might make
  185
+type-checking a tad faster.
  186
+
  187
+### V. Mutability.
  188
+
  189
+Mutability is bad. You have no idea how bad it is until you've attempted to
  190
+execute mutable code in parallel. Consequently, mutable code should be
  191
+avoided. Really.
  192
+
  193
+In the current versions of Opa, the unit of mutability is the session. If you
  194
+need mutability, use a session. If you need a global state shared by the server,
  195
+use [UserContext]. If you need something to be saved for future uses, use the
  196
+database. Don't write volatile stuff into the database. No sessions, no session
  197
+identifiers, etc.
  198
+
  199
+If you have a use case that fits none of these, and if you are really convinced
  200
+that you need a reference, come and see David.  He might scream at you, of
  201
+course.
  202
+
  203
+### V. Interacting with the compiler.
  204
+
  205
+If you define a value which needs to be used by the compiler, there are a few
  206
+steps you need to take in order to make sure that it won't be removed
  207
+prematurely by a compiler optimization and/or by the persons maintaining the
  208
+library.
  209
+
  210
+For this purpose, you should
  211
+
  212
+- mark your value as @opacapi
  213
+- add it to opacapi/opacapi.ml
  214
+- in some cases, add it to the roots
  215
+- document how and why it's used in the compiler
  216
+
  217
+### VI. Checking that it works.
  218
+
  219
+Compile with the normal procedure (make), and run tests.
  220
+
  221
+### VII. Bypasses.
  222
+
  223
+Make what you want with bypasses. Do not export private bypasses.
  224
+
  225
+### VIII. Fold, map, etc.
  226
+
  227
+The base loops upon each data structure are
  228
+
  229
+- fold, foldi
  230
+- map, mapi
  231
+- iter, iteri
  232
+- filter, filteri
  233
+- reduce, reducei
  234
+- filter_map, filter_mapi
  235
+
  236
+Wherever possible, data structures should also support constructors
  237
+
  238
+- unfold, unfoldi
  239
+- init
  240
+- of_list
  241
+
  242
+And conversion to external data structures
  243
+
  244
+- to_list
  245
+- to_map
  246
+
  247
+Unless your data structure doesn't support these constructions, they should all exist, exactly with this name.
  248
+If your data structure supports several folds (or several maps, etc), one of them, the default one, must be
  249
+called exactly "fold" (respectively "map"). Name the variants with a suffix, which makes the difference explicit
  250
+(e.g. "fold" -> "fold_backwards", "iteri" -> "iteri_backwards", etc.)
  251
+
  252
+The order of arguments is the following, keep it consistent for all data structures:
  253
+
  254
+function ( iterator, structure, [more-arguments]) : 'result
  255
+
  256
+- exists:      ( f:('a -> bool),               structure: t('a)               ): bool
  257
+
  258
+- filter:      ( f:'a -> bool,                 structure: t('a)               ): t('a)
  259
+- filteri:     ( f:int -> 'a -> bool,          structure: t('a)               ): t('a)
  260
+- filter_map:  ( f:'a -> option('b),           structure: t('a)               ): t('b)
  261
+- filter_mapi: ( f:int -> 'a -> option('b),    structure: t('a)               ): t('b)
  262
+
  263
+- fold:        ( f:('item, 'acc) -> 'acc,      structure: t('item), init:'acc ): 'acc
  264
+- foldi:       ( f:(int, 'item, 'acc) -> 'acc, structure: t('item), init:'acc ): 'acc
  265
+
  266
+- init:        ( f:int -> 'item, size: int):                                     t('item)
  267
+
  268
+- iter:        ( f:('a -> void),               structure: t('a)               ): void
  269
+- iteri:       ( f:(int, 'a) -> void,          structure: t('a)               ): void
  270
+
  271
+- map:         ( f:'a -> 'b,                   structure: t('a)               ): t('b)
  272
+- mapi:        ( f:(int,'a) -> 'b,             structure: t('a)               ): t('b)
  273
+
  274
+- mem:         ( elt:'a,                       structure: t('a)               ): bool
  275
+
  276
+- reduce:      ( f:'a -> 'a,                   structure: t('a)               ): option('a) //{none} if the structure was empty
  277
+- reducei:     ( f:int -> 'a -> 'a,            structure: t('a)               ): option('a) //{none} if the structure was empty
  278
+
  279
+- unfold:      ( f:'counter -> option(('item, 'counter)), init: 'counter      ): t('item)
  280
+- unfoldi:     ( f:(int, 'counter)-> option(('item, 'counter)), init: 'counter): t('item)
  281
+
  282
+
40 283
 <!--
41 284
 # Opa Documentation format :
42 285
 
234  lib/stdlib/GUIDELINES
... ...
@@ -1,234 +0,0 @@
1  
-==== How to write an OPA module ====
2  
-
3  
-Read this before writing an OPA module.
4  
-If you don't, chances are that the module will not be kept.
5  
-
6  
-The role of these guidelines is to make sure that:
7  
-+ we can find our way in the code easily
8  
-+ we produce documentation for end-users
9  
-+ your changes break neither the compiler nor the user's code.
10  
-
11  
-==== I. All code must be documented. ========
12  
-
13  
-For examples of documented code, see the existing code.
14  
-Try to stay as much as possible is the same spirit, and
15  
-check that the generated html (opadoc) is well formed.
16  
-
17  
-Documenting takes only a few minutes.
18  
-Understanding undocumented code takes hours or days.
19  
-If you don't document your code, someone will hate you passionately.
20  
-You have been warned.
21  
-
22  
-Important Note: Don't confuse "commenting" and "documenting".
23  
-Comments are good but can't replace documentation.
24  
-Again, see the examples.
25  
-
26  
-Documentation MUST indicate, among other things
27  
-- what the module is for
28  
-- who it is for ("@audience PUBLIC"/"@audience PRIVATE"/...)
29  
-- possibly, how it is used, by who, in particular for modules of stdlib.core,
30  
-because any change in this kind of modules can have an impact on the compiler.
31  
-
32  
-For an example of documentation, see DOCUMENTING, in this directory,
33  
-or see all the existing documentation.
34  
-
35  
-==== II. How should I call my module? Where should I put it? ========
36  
-
37  
-We have a notion of packages. The compiler is fully separated with respect to
38  
-packages.
39  
-
40  
-The main criterium for the separation of files is the packages dependencies.
41  
-
42  
-Package names can be named with a '.' (dot), but it is a fake hierarchy.  In
43  
-fact, a dot can be seen like an underscore, and packages are identifying by
44  
-their names, so, if it is not needed, do not go too deep in the hierarchy.
45  
-
46  
-II.1) stdlib.core
47  
-
48  
-If your module is used by the compiler, it must go to : stdlib.core
49  
-This package is needed for core opa features, it contains mostly run time
50  
-support, like comparison, serialization, servers codes.
51  
-
52  
-This package also defines its own interface for the compiler, i.e. the complete
53  
-set of function the compiler can insert calls on. This interface is declared by declaration tagged by @opacapi directives.
54  
-Theses declarations should only be toplevel aliases, on functions in stdlib.core,
55  
-and the name of each alias must be the full path of the function with dots
56  
-replaced by underscores.
57  
-E.g. : Value_serialize = Value.serialize
58  
-
59  
-Be extremly aware of the fact that we are trying to reduce as much as possible
60  
-the size of the minimal server. This has also an important impact on the debugging.
61  
-If your module is not used by the compiler, then, it has really nothing to do in stdlib.core.
62  
-If you add a lot of code in stdlib.core, someone will hate you passionately.
63  
-You have been warned.
64  
-
65  
-II.2) stdlib.*
66  
-
67  
-These packages are additionnaly libs we want to be part of the standard library.
68  
-It is still not really clear if a package should be in the stdlib, or not.
69  
-Probably most of generic packages developped @mlstate will be in stdlib.*
70  
-
71  
-If your package is too specific, then it is probably better to make a separate package.
72  
-
73  
-some example:
74  
-  facebook -> not is stdlib, TODO: specify the package organisation.
75  
-  fgraph -> stdlib.fgraph
76  
-
77  
-If you want to add several modules related to the same thing, it would be preferable
78  
-to create a new package. (cf e.g. fgraph)
79  
-If your module is an extension of an existing package, simply add it in the corresponding package.
80  
-
81  
-==== III. Code goes into modules. ====
82  
-
83  
-Remember, by default, in OPA, everything sits in the current package namespace.
84  
-Every typename and every value name you create therefore pollutes the current package namespace,
85  
-potentially breaking someone else's code.
86  
-
87  
-Consequently, all your values must be in modules, and/or restricting the interfaces
88  
-with the scopes directives :
89  
-@public
90  
-@package
91  
-@private
92  
-
93  
-Similarly, all your types should respect the namespace conventions.
94  
-For the moment, we don't have a syntax to put types into record.
95  
-Until then, if you wish to add a type "foo" to your module "Foo", call it "Foo.foo".
96  
-The name of types should strictly follow the hierarchy of modules.
97  
-
98  
-If you wish to add a function or a type to the global namespace, ask the opa team first.
99  
-Be aware that big changes in the stdlib are dangerous because of the number of potential
100  
-users which already use it.
101  
-Be aware that if you add a function with a ugly name (or even worth, a function with a
102  
-name incoherent with the implementation), someone could use it the next day,
103  
-and if you want to change some names, and types after that, it will imply a big refactoring
104  
-everywhere your functions are used.
105  
-
106  
-If you add function which does not follow naming conventions, or argument order conventions,
107  
-or any other conventions written in this file, someone will hate you passionately.
108  
-You have been warned.
109  
-
110  
-Remember that once a OPA distribution will be done, we will no more be able to change any interfaces !
111  
-There is no hurry. Take your time. Review your code, ask advice for names of functions to other people,
112  
-it is always good to have several point of vues.
113  
-See also if a correspond lib does not already exists in an other language.
114  
-For exemple, if there is a reference API in an other language, you can keep the same names
115  
-(convention used e.g. in fgraph, the API is mostly preserved from OcamlGraph)
116  
-
117  
-Let's say we are playing in a contest of beauty of API.
118  
-
119  
-==== IV. Naming conventions. ====
120  
-
121  
-values_look_like_this
122  
-ModuleLookLikeThis
123  
-TypesInModule.Look.like_this
124  
-fields_look_like_this
125  
-files_look_like_this.opa
126  
-
127  
-Accessor functions:
128  
-
129  
-get_foo
130  
-is_foo
131  
-
132  
-Conversion functions:
133  
-
134  
-Foo.of_bar
135  
-Foo.to_bar
136  
-
137  
-==== IV. Types are closed. ====
138  
-
139  
-When you define a new type or data structure, chances are that users don't need
140  
-to know how it's implemented, so you should make it @abstract (if users should
141  
-see the type but not its definition) or @private (if the type is purely
142  
-internal). This will make error messages simpler for the user and it might make
143  
-type-checking a tad faster.
144  
-
145  
-==== V. Mutability. ====
146  
-
147  
-Mutability is bad. You have no idea how bad it is until you've attempted to
148  
-execute mutable code in parallel. Consequently, mutable code should be
149  
-avoided. Really.
150  
-
151  
-In the current versions of OPA, the unit of mutability is the session. If you
152  
-need mutability, use a session. If you need a global state shared by the server,
153  
-use [UserContext]. If you need something to be saved for future uses, use the
154  
-database. Don't write volatile stuff into the database. No sessions, no session
155  
-identifiers, etc.
156  
-
157  
-If you have a use case that fits none of these, and if you are really convinced
158  
-that you need a reference, come and see David.  He might scream at you, of
159  
-course.
160  
-
161  
-==== V. Interacting with the compiler. ===
162  
-
163  
-If you define a value which needs to be used by the compiler, there are a few
164  
-steps you need to take in order to make sure that it won't be removed
165  
-prematurely by a compiler optimization and/or by the persons maintaining the
166  
-library.
167  
-
168  
-For this purpose, you should
169  
-- mark your value as @opacapi
170  
-- add it to opacapi/opacapi.ml
171  
-- in some cases, add it to the roots
172  
-- document how and why it's used in the compiler
173  
-
174  
-==== VI. Checking that it works. ===
175  
-
176  
-Compile with the normal procedure (make), and run tests.
177  
-
178  
-==== VII. Bypasses ===
179  
-
180  
-Make what you want with bypasses. Do not export private bypasses.
181  
-
182  
-==== VIII. Fold, map, etc. ===
183  
-
184  
-The base loops upon each data structure are
185  
-- fold, foldi
186  
-- map, mapi
187  
-- iter, iteri
188  
-- filter, filteri
189  
-- reduce, reducei
190  
-- filter_map, filter_mapi
191  
-
192  
-Wherever possible, data structures should also support constructors
193  
-- unfold, unfoldi
194  
-- init
195  
-- of_list
196  
-
197  
-And conversion to external data structures
198  
-- to_list
199  
-- to_map
200  
-
201  
-Unless your data structure doesn't support these constructions, they should all exist, exactly with this name.
202  
-If your data structure supports several folds (or several maps, etc), one of them, the default one, must be
203  
-called exactly "fold" (respectively "map"). Name the variants with a suffix, which makes the difference explicit
204  
-(e.g. "fold" -> "fold_backwards", "iteri" -> "iteri_backwards", etc.)
205  
-
206  
-The order of arguments is the following, keep it consistent for all data structures:
207  
-
208  
-function ( iterator, structure, [more-arguments]) : 'result
209  
-
210  
-- exists:      ( f:('a -> bool),               structure: t('a)               ): bool
211  
-
212  
-- filter:      ( f:'a -> bool,                 structure: t('a)               ): t('a)
213  
-- filteri:     ( f:int -> 'a -> bool,          structure: t('a)               ): t('a)
214  
-- filter_map:  ( f:'a -> option('b),           structure: t('a)               ): t('b)
215  
-- filter_mapi: ( f:int -> 'a -> option('b),    structure: t('a)               ): t('b)
216  
-
217  
-- fold:        ( f:('item, 'acc) -> 'acc,      structure: t('item), init:'acc ): 'acc
218  
-- foldi:       ( f:(int, 'item, 'acc) -> 'acc, structure: t('item), init:'acc ): 'acc
219  
-
220  
-- init:        ( f:int -> 'item, size: int):                                     t('item)
221  
-
222  
-- iter:        ( f:('a -> void),               structure: t('a)               ): void
223  
-- iteri:       ( f:(int, 'a) -> void,          structure: t('a)               ): void
224  
-
225  
-- map:         ( f:'a -> 'b,                   structure: t('a)               ): t('b)
226  
-- mapi:        ( f:(int,'a) -> 'b,             structure: t('a)               ): t('b)
227  
-
228  
-- mem:         ( elt:'a,                       structure: t('a)               ): bool
229  
-
230  
-- reduce:      ( f:'a -> 'a,                   structure: t('a)               ): option('a) //{none} if the structure was empty
231  
-- reducei:     ( f:int -> 'a -> 'a,            structure: t('a)               ): option('a) //{none} if the structure was empty
232  
-
233  
-- unfold:      ( f:'counter -> option(('item, 'counter)), init: 'counter      ): t('item)
234  
-- unfoldi:     ( f:(int, 'counter)-> option(('item, 'counter)), init: 'counter): t('item)

0 notes on commit f5b2865

Please sign in to comment.
Something went wrong with that request. Please try again.