Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[doc] CONTRIBUTING: merged stdlib guidelines

  • Loading branch information...
commit f5b2865705e5a4027b3fa0a52ded34a677bdb349 1 parent fb77bd1
@Aqua-Ye Aqua-Ye authored
Showing with 243 additions and 234 deletions.
  1. +243 −0 CONTRIBUTING.md
  2. +0 −234 lib/stdlib/GUIDELINES
View
243 CONTRIBUTING.md
@@ -37,6 +37,249 @@ YEAR.MONTH.DAY, Version SEMVER (stability), GIT_HASH
* change 3
+# Stdlib
+
+## How to write an Opa module
+
+Read this before writing an Opa module.
+If you don't, chances are that the module will not be kept.
+
+The role of these guidelines is to make sure that:
+
+- we can find our way in the code easily
+- we produce documentation for end-users
+- your changes break neither the compiler nor the user's code.
+
+### I. All code must be documented.
+
+For examples of documented code, see the existing code.
+Try to stay as much as possible is the same spirit, and
+check that the generated html (opadoc) is well formed.
+
+Documenting takes only a few minutes.
+Understanding undocumented code takes hours or days.
+If you don't document your code, someone will hate you passionately.
+You have been warned.
+
+Important Note: Don't confuse "commenting" and "documenting".
+Comments are good but can't replace documentation.
+Again, see the examples.
+
+Documentation MUST indicate, among other things
+- what the module is for
+- who it is for ("@audience PUBLIC"/"@audience PRIVATE"/...)
+- possibly, how it is used, by who, in particular for modules of stdlib.core,
+because any change in this kind of modules can have an impact on the compiler.
+
+For an example of documentation, see DOCUMENTING, in this directory,
+or see all the existing documentation.
+
+### II. How should I call my module? Where should I put it?
+
+We have a notion of packages. The compiler is fully separated with respect to
+packages.
+
+The main criterium for the separation of files is the packages dependencies.
+
+Package names can be named with a '.' (dot), but it is a fake hierarchy. In
+fact, a dot can be seen like an underscore, and packages are identifying by
+their names, so, if it is not needed, do not go too deep in the hierarchy.
+
+#### II.1) stdlib.core
+
+If your module is used by the compiler, it must go to : stdlib.core
+This package is needed for core Opa features, it contains mostly run time
+support, like comparison, serialization, servers codes.
+
+This package also defines its own interface for the compiler, i.e. the complete
+set of function the compiler can insert calls on. This interface is declared by declaration tagged by @opacapi directives.
+Theses declarations should only be toplevel aliases, on functions in stdlib.core,
+and the name of each alias must be the full path of the function with dots
+replaced by underscores.
+E.g. : Value_serialize = Value.serialize
+
+Be extremly aware of the fact that we are trying to reduce as much as possible
+the size of the minimal server. This has also an important impact on the debugging.
+If your module is not used by the compiler, then, it has really nothing to do in stdlib.core.
+If you add a lot of code in stdlib.core, someone will hate you passionately.
+You have been warned.
+
+##### II.2) stdlib.*
+
+These packages are additionnaly libs we want to be part of the standard library.
+It is still not really clear if a package should be in the stdlib, or not.
+Probably most of generic packages developped @mlstate will be in stdlib.*
+
+If your package is too specific, then it is probably better to make a separate package.
+
+some example:
+ facebook -> not is stdlib, TODO: specify the package organisation.
+ fgraph -> stdlib.fgraph
+
+If you want to add several modules related to the same thing, it would be preferable
+to create a new package. (cf e.g. fgraph)
+If your module is an extension of an existing package, simply add it in the corresponding package.
+
+### III. Code goes into modules.
+
+Remember, by default, in Opa, everything sits in the current package namespace.
+Every typename and every value name you create therefore pollutes the current package namespace,
+potentially breaking someone else's code.
+
+Consequently, all your values must be in modules, and/or restricting the interfaces
+with the scopes directives :
+`@public`
+`@package`
+`@private`
+
+Similarly, all your types should respect the namespace conventions.
+For the moment, we don't have a syntax to put types into record.
+Until then, if you wish to add a type "foo" to your module "Foo", call it "Foo.foo".
+The name of types should strictly follow the hierarchy of modules.
+
+If you wish to add a function or a type to the global namespace, ask the Opa team first.
+Be aware that big changes in the stdlib are dangerous because of the number of potential
+users which already use it.
+Be aware that if you add a function with a ugly name (or even worth, a function with a
+name incoherent with the implementation), someone could use it the next day,
+and if you want to change some names, and types after that, it will imply a big refactoring
+everywhere your functions are used.
+
+If you add function which does not follow naming conventions, or argument order conventions,
+or any other conventions written in this file, someone will hate you passionately.
+You have been warned.
+
+Remember that once a Opa distribution will be done, we will no more be able to change any interfaces !
+There is no hurry. Take your time. Review your code, ask advice for names of functions to other people,
+it is always good to have several point of vues.
+See also if a correspond lib does not already exists in an other language.
+For exemple, if there is a reference API in an other language, you can keep the same names
+(convention used e.g. in fgraph, the API is mostly preserved from OcamlGraph)
+
+Let's say we are playing in a contest of beauty of API.
+
+### IV. Naming conventions.
+
+values_look_like_this
+ModuleLookLikeThis
+TypesInModule.Look.like_this
+fields_look_like_this
+files_look_like_this.opa
+
+Accessor functions:
+
+get_foo
+is_foo
+
+Conversion functions:
+
+Foo.of_bar
+Foo.to_bar
+
+### IV. Types are closed.
+
+When you define a new type or data structure, chances are that users don't need
+to know how it's implemented, so you should make it @abstract (if users should
+see the type but not its definition) or @private (if the type is purely
+internal). This will make error messages simpler for the user and it might make
+type-checking a tad faster.
+
+### V. Mutability.
+
+Mutability is bad. You have no idea how bad it is until you've attempted to
+execute mutable code in parallel. Consequently, mutable code should be
+avoided. Really.
+
+In the current versions of Opa, the unit of mutability is the session. If you
+need mutability, use a session. If you need a global state shared by the server,
+use [UserContext]. If you need something to be saved for future uses, use the
+database. Don't write volatile stuff into the database. No sessions, no session
+identifiers, etc.
+
+If you have a use case that fits none of these, and if you are really convinced
+that you need a reference, come and see David. He might scream at you, of
+course.
+
+### V. Interacting with the compiler.
+
+If you define a value which needs to be used by the compiler, there are a few
+steps you need to take in order to make sure that it won't be removed
+prematurely by a compiler optimization and/or by the persons maintaining the
+library.
+
+For this purpose, you should
+
+- mark your value as @opacapi
+- add it to opacapi/opacapi.ml
+- in some cases, add it to the roots
+- document how and why it's used in the compiler
+
+### VI. Checking that it works.
+
+Compile with the normal procedure (make), and run tests.
+
+### VII. Bypasses.
+
+Make what you want with bypasses. Do not export private bypasses.
+
+### VIII. Fold, map, etc.
+
+The base loops upon each data structure are
+
+- fold, foldi
+- map, mapi
+- iter, iteri
+- filter, filteri
+- reduce, reducei
+- filter_map, filter_mapi
+
+Wherever possible, data structures should also support constructors
+
+- unfold, unfoldi
+- init
+- of_list
+
+And conversion to external data structures
+
+- to_list
+- to_map
+
+Unless your data structure doesn't support these constructions, they should all exist, exactly with this name.
+If your data structure supports several folds (or several maps, etc), one of them, the default one, must be
+called exactly "fold" (respectively "map"). Name the variants with a suffix, which makes the difference explicit
+(e.g. "fold" -> "fold_backwards", "iteri" -> "iteri_backwards", etc.)
+
+The order of arguments is the following, keep it consistent for all data structures:
+
+function ( iterator, structure, [more-arguments]) : 'result
+
+- exists: ( f:('a -> bool), structure: t('a) ): bool
+
+- filter: ( f:'a -> bool, structure: t('a) ): t('a)
+- filteri: ( f:int -> 'a -> bool, structure: t('a) ): t('a)
+- filter_map: ( f:'a -> option('b), structure: t('a) ): t('b)
+- filter_mapi: ( f:int -> 'a -> option('b), structure: t('a) ): t('b)
+
+- fold: ( f:('item, 'acc) -> 'acc, structure: t('item), init:'acc ): 'acc
+- foldi: ( f:(int, 'item, 'acc) -> 'acc, structure: t('item), init:'acc ): 'acc
+
+- init: ( f:int -> 'item, size: int): t('item)
+
+- iter: ( f:('a -> void), structure: t('a) ): void
+- iteri: ( f:(int, 'a) -> void, structure: t('a) ): void
+
+- map: ( f:'a -> 'b, structure: t('a) ): t('b)
+- mapi: ( f:(int,'a) -> 'b, structure: t('a) ): t('b)
+
+- mem: ( elt:'a, structure: t('a) ): bool
+
+- reduce: ( f:'a -> 'a, structure: t('a) ): option('a) //{none} if the structure was empty
+- reducei: ( f:int -> 'a -> 'a, structure: t('a) ): option('a) //{none} if the structure was empty
+
+- unfold: ( f:'counter -> option(('item, 'counter)), init: 'counter ): t('item)
+- unfoldi: ( f:(int, 'counter)-> option(('item, 'counter)), init: 'counter): t('item)
+
+
<!--
# Opa Documentation format :
View
234 lib/stdlib/GUIDELINES
@@ -1,234 +0,0 @@
-==== How to write an OPA module ====
-
-Read this before writing an OPA module.
-If you don't, chances are that the module will not be kept.
-
-The role of these guidelines is to make sure that:
-+ we can find our way in the code easily
-+ we produce documentation for end-users
-+ your changes break neither the compiler nor the user's code.
-
-==== I. All code must be documented. ========
-
-For examples of documented code, see the existing code.
-Try to stay as much as possible is the same spirit, and
-check that the generated html (opadoc) is well formed.
-
-Documenting takes only a few minutes.
-Understanding undocumented code takes hours or days.
-If you don't document your code, someone will hate you passionately.
-You have been warned.
-
-Important Note: Don't confuse "commenting" and "documenting".
-Comments are good but can't replace documentation.
-Again, see the examples.
-
-Documentation MUST indicate, among other things
-- what the module is for
-- who it is for ("@audience PUBLIC"/"@audience PRIVATE"/...)
-- possibly, how it is used, by who, in particular for modules of stdlib.core,
-because any change in this kind of modules can have an impact on the compiler.
-
-For an example of documentation, see DOCUMENTING, in this directory,
-or see all the existing documentation.
-
-==== II. How should I call my module? Where should I put it? ========
-
-We have a notion of packages. The compiler is fully separated with respect to
-packages.
-
-The main criterium for the separation of files is the packages dependencies.
-
-Package names can be named with a '.' (dot), but it is a fake hierarchy. In
-fact, a dot can be seen like an underscore, and packages are identifying by
-their names, so, if it is not needed, do not go too deep in the hierarchy.
-
-II.1) stdlib.core
-
-If your module is used by the compiler, it must go to : stdlib.core
-This package is needed for core opa features, it contains mostly run time
-support, like comparison, serialization, servers codes.
-
-This package also defines its own interface for the compiler, i.e. the complete
-set of function the compiler can insert calls on. This interface is declared by declaration tagged by @opacapi directives.
-Theses declarations should only be toplevel aliases, on functions in stdlib.core,
-and the name of each alias must be the full path of the function with dots
-replaced by underscores.
-E.g. : Value_serialize = Value.serialize
-
-Be extremly aware of the fact that we are trying to reduce as much as possible
-the size of the minimal server. This has also an important impact on the debugging.
-If your module is not used by the compiler, then, it has really nothing to do in stdlib.core.
-If you add a lot of code in stdlib.core, someone will hate you passionately.
-You have been warned.
-
-II.2) stdlib.*
-
-These packages are additionnaly libs we want to be part of the standard library.
-It is still not really clear if a package should be in the stdlib, or not.
-Probably most of generic packages developped @mlstate will be in stdlib.*
-
-If your package is too specific, then it is probably better to make a separate package.
-
-some example:
- facebook -> not is stdlib, TODO: specify the package organisation.
- fgraph -> stdlib.fgraph
-
-If you want to add several modules related to the same thing, it would be preferable
-to create a new package. (cf e.g. fgraph)
-If your module is an extension of an existing package, simply add it in the corresponding package.
-
-==== III. Code goes into modules. ====
-
-Remember, by default, in OPA, everything sits in the current package namespace.
-Every typename and every value name you create therefore pollutes the current package namespace,
-potentially breaking someone else's code.
-
-Consequently, all your values must be in modules, and/or restricting the interfaces
-with the scopes directives :
-@public
-@package
-@private
-
-Similarly, all your types should respect the namespace conventions.
-For the moment, we don't have a syntax to put types into record.
-Until then, if you wish to add a type "foo" to your module "Foo", call it "Foo.foo".
-The name of types should strictly follow the hierarchy of modules.
-
-If you wish to add a function or a type to the global namespace, ask the opa team first.
-Be aware that big changes in the stdlib are dangerous because of the number of potential
-users which already use it.
-Be aware that if you add a function with a ugly name (or even worth, a function with a
-name incoherent with the implementation), someone could use it the next day,
-and if you want to change some names, and types after that, it will imply a big refactoring
-everywhere your functions are used.
-
-If you add function which does not follow naming conventions, or argument order conventions,
-or any other conventions written in this file, someone will hate you passionately.
-You have been warned.
-
-Remember that once a OPA distribution will be done, we will no more be able to change any interfaces !
-There is no hurry. Take your time. Review your code, ask advice for names of functions to other people,
-it is always good to have several point of vues.
-See also if a correspond lib does not already exists in an other language.
-For exemple, if there is a reference API in an other language, you can keep the same names
-(convention used e.g. in fgraph, the API is mostly preserved from OcamlGraph)
-
-Let's say we are playing in a contest of beauty of API.
-
-==== IV. Naming conventions. ====
-
-values_look_like_this
-ModuleLookLikeThis
-TypesInModule.Look.like_this
-fields_look_like_this
-files_look_like_this.opa
-
-Accessor functions:
-
-get_foo
-is_foo
-
-Conversion functions:
-
-Foo.of_bar
-Foo.to_bar
-
-==== IV. Types are closed. ====
-
-When you define a new type or data structure, chances are that users don't need
-to know how it's implemented, so you should make it @abstract (if users should
-see the type but not its definition) or @private (if the type is purely
-internal). This will make error messages simpler for the user and it might make
-type-checking a tad faster.
-
-==== V. Mutability. ====
-
-Mutability is bad. You have no idea how bad it is until you've attempted to
-execute mutable code in parallel. Consequently, mutable code should be
-avoided. Really.
-
-In the current versions of OPA, the unit of mutability is the session. If you
-need mutability, use a session. If you need a global state shared by the server,
-use [UserContext]. If you need something to be saved for future uses, use the
-database. Don't write volatile stuff into the database. No sessions, no session
-identifiers, etc.
-
-If you have a use case that fits none of these, and if you are really convinced
-that you need a reference, come and see David. He might scream at you, of
-course.
-
-==== V. Interacting with the compiler. ===
-
-If you define a value which needs to be used by the compiler, there are a few
-steps you need to take in order to make sure that it won't be removed
-prematurely by a compiler optimization and/or by the persons maintaining the
-library.
-
-For this purpose, you should
-- mark your value as @opacapi
-- add it to opacapi/opacapi.ml
-- in some cases, add it to the roots
-- document how and why it's used in the compiler
-
-==== VI. Checking that it works. ===
-
-Compile with the normal procedure (make), and run tests.
-
-==== VII. Bypasses ===
-
-Make what you want with bypasses. Do not export private bypasses.
-
-==== VIII. Fold, map, etc. ===
-
-The base loops upon each data structure are
-- fold, foldi
-- map, mapi
-- iter, iteri
-- filter, filteri
-- reduce, reducei
-- filter_map, filter_mapi
-
-Wherever possible, data structures should also support constructors
-- unfold, unfoldi
-- init
-- of_list
-
-And conversion to external data structures
-- to_list
-- to_map
-
-Unless your data structure doesn't support these constructions, they should all exist, exactly with this name.
-If your data structure supports several folds (or several maps, etc), one of them, the default one, must be
-called exactly "fold" (respectively "map"). Name the variants with a suffix, which makes the difference explicit
-(e.g. "fold" -> "fold_backwards", "iteri" -> "iteri_backwards", etc.)
-
-The order of arguments is the following, keep it consistent for all data structures:
-
-function ( iterator, structure, [more-arguments]) : 'result
-
-- exists: ( f:('a -> bool), structure: t('a) ): bool
-
-- filter: ( f:'a -> bool, structure: t('a) ): t('a)
-- filteri: ( f:int -> 'a -> bool, structure: t('a) ): t('a)
-- filter_map: ( f:'a -> option('b), structure: t('a) ): t('b)
-- filter_mapi: ( f:int -> 'a -> option('b), structure: t('a) ): t('b)
-
-- fold: ( f:('item, 'acc) -> 'acc, structure: t('item), init:'acc ): 'acc
-- foldi: ( f:(int, 'item, 'acc) -> 'acc, structure: t('item), init:'acc ): 'acc
-
-- init: ( f:int -> 'item, size: int): t('item)
-
-- iter: ( f:('a -> void), structure: t('a) ): void
-- iteri: ( f:(int, 'a) -> void, structure: t('a) ): void
-
-- map: ( f:'a -> 'b, structure: t('a) ): t('b)
-- mapi: ( f:(int,'a) -> 'b, structure: t('a) ): t('b)
-
-- mem: ( elt:'a, structure: t('a) ): bool
-
-- reduce: ( f:'a -> 'a, structure: t('a) ): option('a) //{none} if the structure was empty
-- reducei: ( f:int -> 'a -> 'a, structure: t('a) ): option('a) //{none} if the structure was empty
-
-- unfold: ( f:'counter -> option(('item, 'counter)), init: 'counter ): t('item)
-- unfoldi: ( f:(int, 'counter)-> option(('item, 'counter)), init: 'counter): t('item)
Please sign in to comment.
Something went wrong with that request. Please try again.