Typology of Some Programming Practices Or Conventions

Ph. A. Martin


Goal/use, structure and reading of this file:


Table of Contents

1. General Goals, Definitions and PPs 1.1. General Goals: Normalizing Programs For Understandability, Maintenance, Scalability, Translatability and Genericity Purposes 1.2. Other General Definitions 1.3. Most General PPs 2. Structural Representation PPs (→ Programming Paradigm, Modularity, Structural Normalization, ...) and Lexical Representation PPs (→ Naming PPs, Lexical Normalization, ...) 2.1. General Representation PPs For Genericity/Re-usability Purposes 2.2. Function Names and Parameters (PP_2.2: using good function names+parameters) 2.3. Variable Names (PP_2.3: using good/useful variable names, essentially, informative ones, even if long) 2.4. Other Names: File Names, XML Names, ... 2.5. About Documentations 2.6. About Inputs and Outputs: User Interfaces, ... 3. Non-Structural/Lexical PPs (→ Programming Style) 3.1. Function Size and Space/Indentation Related PPs

1. General Goals, Definitions and PPs

1.1. General Goals: Normalizing Programs For Reusability, Hence For Understandability, Maintenability, Scalability, Translatability and Genericity Purposes

Context: categorization of software quality criteria. Software quality refers to two related notions or sets of criteria:

(Re-)usability. In this document, “reusability” refers to the internal criteria for “dependability but not security”: maintainability and reliability. The notions of scalability, genericity, modularity, translatability (automatically, in other programming languages) and understandability (alias readability; by people) can be seen as sub-criteria of maintainability and then, indirectly, of reliability. In this document, only the internal aspects are considered but these criteria have external consequences, hence related external criteria. Programming is not just about coding a program that seems to solve a given problem for the particular cases that the programmer have thought about, it is about creating a program that is

Normalization. Normalizing a program is to follow programming practices/techniques (PPs) when writing it (notably for the above cited purposes): structural representation PPs (→ programming paradigms, methodologies or (notions of) common APIs), lexical representation PPs (→ naming conventions) and presentation PPs (→ programming style).

1.2. Other General Definitions

The following paragraphs precise the meaning the particular meaning that some terms have in this particular document.

Translation: automatic conversion of operations from a programing language to another.

Operation: function or another statement that uses a programming language.

Function: subroutine (or whole program), whether it return a value or not. Thus, “procedures” and “methods“ are also “functions”.

Method: a function associated to an object, as in object-oriented (O.O.) programming. A function that is not a method is, from now on, called a “normal function”. Note: when a method is translated into a normal function, the object this method is associated to becomes the first parameter of the normal function; hence, below, when the first parameter of a method is referred to, the object is actually referred to.

In/out parameters: a function parameter (alias, argument) may be either

Type: predefined type or user-defined type/class, typically for a variable or a constant. In Javascript, the predefined primitive types (those that can be checked via the “typeof” operator) are: Function, Symbol, Object, String, “undefined”, Boolean, Number (and BigInt). However, Javascript also proposes other types such as Array, Date, RegExp, Set and Error. The (static or dynamic) type checking of an operation is the automatic checking that the operation does not violate constraints associated to the types of the variables involved in the operation. The checking is static if it is performed at compilation time and dynamic if it is performed at execution time.

Program: collection of functions.

Process: execution of a program. Each process has its own id, allocated memory, etc.
Thread: execution of the smallest collection of functions (from a program, hence generally within a process) that can be run by a scheduler: a thread is a unit of execution. Different threads of a process shares the memory (variables, ...) of this process. Different threads may be run in parallel but functions within a thread may not. In this file, this is the absence of parallelism within functions of a thread that is important.

User (of a program):

Generic. In this document, “generic” means i) scalable, and ii) not tied to particular choices (e.g., of data structure, technique and communication medium, ...). This last point implies that, if some choices are handled, many are handled (as many as possible) and that the end-user may choose between them.

Informal (as opposed to semi-formal or fully formal): represented in a way that the used software (compiler, ...) cannot exploit. In semi-formal representations, the software understands some general structure but not the full content. E.g., for a compiler, (discarded) comments are informal, (stored) annotations and identifiers are very weakly semi-formal (the compiler know what they are), while pragmas and any keyword of the parsed language is formal.

Knowledge (Representations;  KRs): information that is, at least partially, represented and organized i) in some logics, and ii) via by semantic relations (e.g. subtype, part, instrument, result, time, place, ... and hundreds more).
Data: information that is not a collection of KRs.
Note: these two definitions make "information" a generalization of data and knowledge, which is coherent with the fact that KR bases/repositories and data bases/repositories are also (usually considered as) information repositories. There are other definitions of "information" with refer to an intermediary between "data" and "knowledge" (e.g., for some of these definitions, "information" is "data + semantics", while "knowledge" is "information + entailment"). These other definitions are not followed in this document.

Knowledge Base  (KB): a collection of terms or KRs, composed of

Database: collection of terms and information that is not a KB but which, instead of an ontology, has a fixed structural schema (only the creator of the database can update it, not end-users, and, except in deductive databases, the programmer cannot define relations in this schema). Databases, even deductive databases, do not allow their users to define new types of relations and do not allow them to relate objects via explicit semantic relations except sometimes via relations of a few predefined kinds such as "subtype Of" and "instance Of". An XML document is not a relational database but be viewed as a database.

DB management system (DBMS): software managing a DB.
KB management system (KBMS): software managing a KB. A KBMS may be implemented by reusing (and very strongly extending) a DMBS where the structural schema mainly has two kinds of objects: i) concept nodes (objects that can be related by relation nodes, e.g. terms and quantified objects), and ii) relation nodes (or simply “relations” things that relate concept nodes; a relations can only indirectly be related to other ones, via its “reification”, a concept node that refer to this relation).

Instance: anything that is instance of (i.e, that has for type) a predefined or user-defined type or a class.
Individual: anything that cannot have an instance (hence, anything that is not a type or class; thus, a literal is an individual; in itself, a variable is an individual but some variables may have a class as value, i.e. may point to that class).
Note: this definition of individual is most often used in general logics (e.g. 2nd-order logics) and general object-oriented systems (where almost everything has a class, e.g. in Smalltalk). In some more restricted logics (e.g. description logics) or object-oriented systems, some non-type objects (e.g. litterals) are not considered "individuals".

1.3. Most General PPs

PP_1.1 (1st PP advocated by this document, and also the most general and hence most important): supporting choices by the users (→ not making choices for the users but not forcing them to make choices either) and allowing the user to check as much things as possible (with users referring to end-users and programmers). This is an adaptation to “software design” of the more general PP “Letting everyone choose and check everything in an optimal way” which is a PP for any action or decision. This for example means that a program that systematically satisfies this PP should be sufficiently generic to satisfy the following more specialized PPs:

PP_1.2: maximizing the number of complied-to requirements (functional ones and non-functional ones, e.g. PPs), supported features and complementary ways to support them (this last point is also required for letting users choose, as advocated by the previous PP).

2. Structural Representation PPs (→ Programming Paradigm, Modularity, Structural Normalization, ...) and Lexical Representation PPs (→ Naming PPs, Lexical Normalization, ...)

This section groups structural and lexical representation PPs because Section 2.2 is about a PP for naming functions and choosing their parameters.

2.1. General Representation PPs For Genericity/Re-usability Purposes

Programming for genericity/re-usability purposes is about avoiding the loss of information representation (and hence exploitation) opportunities. This includes letting users make choices and extensions, not making these choices for the users.
Many of these PPs are inter-related even when categorized in different sub-sections, e.g. PP_2.1.4.2 (not directly using the functions of a language or of a library that you cannot modify) and PP_2.1.2.1 (not directly relying on particular data types/structures).

PP_2.1.1: avoiding the loss of opportunities to i) represent information in explicit and precise ways (hence in as formal ways as possible), and then ii) automatically check its usages. E.g., it is better to store information in function names than in comments, for two reasons: i) what is stored can be exploited, and ii) when a function with an informative name is used, the reader does not have to find the function definition and its associated comments to get the information and understand what the function does). Similarly, when comments can be replaced by tests (pre-conditions, post-conditions, ...) with informative error messages, it is much better since i) the content of the comment is operationalized (→ checks are performed automatically, not just in the head of the program readers), and ii) not just the program readers that can get the information. Example sub-PPs derived from these examples:

PP_2.1.2: avoiding the loss of opportunities to represent information in (more) generic ways. E.g.:

PP_2.1.3: avoiding the loss of opportunities to represent information in (more) standard and inter-related ways. This for example implies

PP_2.1.4: avoiding the loss of modularity opportunities: managing different aspects separately (→ separation of concerns). E.g., the following aspects should each be handled by different (and generic) functions: i) each of the aspects that can be fully handled client-side, typically, all or most of the handling of inputs, outputs, errors and communications with the users or other agents (information prviders or consumers), ii) each of the aspects that can be fully handled server-side, typically, database handlings. At least three paradigms are complementary powerful ways to modularize and normalize the representation of functions: i) object-oriented (O.O.) programming (OOP), ii) functional programming (FP), especially the use of function as parameters and the use of immutable data), and iii) aspect-oriented programming (AOP). Even when a language does not offer particular facility to support them, these paradigms can be adopted: O.O. can be simulated in any language (cf. PP_2.2.1); FP and AOP can be simulated in any language that allow variables to contain (pointers to) functions (via function pre-conditions and post-conditions for AOPs; cf. end of PP_2.2.3). Example sub-PPs:

PP_2.1.5: avoiding the loss of data or access to data (when this is relevant).

2.2. Function Names and Parameters (PP_2.2: using good function names+parameters)

PP_2.2.1: using either methods (hence the O.O. approach) or "pseudo-methods" (normal functions that mimic the O.O. approach). The O.O. approach has modularization advantages. Furthermore, this approach generally leads to method names that are shorter and more normalized than normal function names since the class to which a method is associated (its first genuine parameter) is already explicit and hence is never referred to in a method name. When using the O.O. paradigm is impossible (e.g., because the target language does not support it) or insufficient (details further below), this paradigm can be mimicked with normal functions, which are then here called "pseudo-methods":

Using a pseudo-method is particularly useful for associating a function to several classes that cannot be modified, without having to introduce a superclass for these classes and then having to create instances of this superclass. E.g., the pseudo-method "str_toNumber" can be implemented i) in Javascript as having an object of class String as first parameter, and ii) in C++, as having a char pointer as first parameter (and, since C++ supports polymorphism, it can also be implemented as having an instance of the C++ standard library class "string" as first parameter). Thus, pseudo-methods are particularly useful to use the same functions for different implementations of collections (strings, arrays, ...) and functions, whether they are class instances or not (e.g. functions: they are class instances in Javascript but not in C++).

PP_2.2.2: specifying the types of parameters. In many interpreted languages, parameters – or, more generally, variables – are not typed, and hence not type checked. This is detrimental since static or dynamic type checking often permit the detection of many errors. When variable uses are not checked statically, i.e. at compilation time, an easy way to check that the content of most variables comply to their types is to check these types via dynamic types checks of parameters, since most variables are used in functions. PP_2.2.3 provides more details. As noted in PP_2.1.1.3, there are at least two non-exclusive ways to do specify variable types in a non (fully) formal way: i) using comments, e.g., by prefixing each parameter with its type within parameters, and ii) using special prefixes in variable names, as illustrated in PP_2.3.

PP_2.2.3: checking the types of parameters via function preconditions and postconditions when not all check may be performed statically. The rationale for the dynamic checking of parameters (when it is not fully done statically) have been given by the previous paragraph. Even when static checks occurs, some constraints sometimes cannot be expressed via types (e.g., interval-based value ranges) and then can be checked via dynamic type checks of parameters. To do so, each function may call a type-checking function to check its parameters and, in its return value statements, also call a type-checking function. These precondition and post-condition functions may also be used as aspect-oriented programming (AOP) devices: these functions may retrieve and check preconditions and post-conditions that users have associated to functions.

PP_2.2.4: besides their types, giving as many other precisions about the parameters, e.g., whether they are i) “in” (alias, “inP” or “constP”), “in-out” (alias, “varP”) or “out” (alias, “outP”), ii) created/allocated or freed by the function, and iii) lazy-evaluated or not.

PP_2.2.5: using functions that have no side effect other than via the modification of their first or last parameter (i.e., the only “in-out” parameter(s) is/are the first and/or last one; for a method, the first paramether is the object the method is associated to), for normalization purpose and to ease the translation of functions into pure functions. A pure function does not have side effects and hence, for example, only has “in” parameters. To mimic side effects via pure functions (and still support function composability) pure functional languages for example propose the use of monads. An intuitive generalization of the idea behind monads is that, if, besides local variables, each function in a thread only modifies some parameter(s) that are; – or could easily be – used; as; (or aggregated into) the return value of the function, this function can be easily represented into a pure functional language. With a method, instead of an explicit aggregation of modified parameters into the return value, if the modified parameters are part of – or referred by – the object on which this method is called, function composability can be indirectly achieved by using the same modified object(s) in later function/method calls (indeed, pure functions can be chained if they return the object that they modify or if they return this object and an additional return value by aggregating both of them). More intuitively, this means that all objects used as modified parameters should i) be part of – or referred by – a same “Environment” object which in pure functional language can be transformed into a monad, and ii) refer to this Environment” object which then is (directly or indirectly) the global object/monad modified by all method/functions. In theory, to avoid genuine modifications, only a modified copy may be returned by a pure function but, in a chain of functions, directly modifying and returning the same object is not problematic for keeping the advantages of pure functions. Although a function modifying many parameters could be translated into a pure function that aggregate and return (copies of) the modified parameters, the restriction (PP) of modifying only the first and/or last parameter of functions – with the additional conventions that i) the function is then an actual or simulated method for this first parameter, and ii) the function returns this last modified parameters if it is different form the first – ease i) the translation of the program into a purely functional language, and ii) the understanding of these functions by people (they know exactly which parameters are modified and how they are returned).
PP_2.2.5.1: this (kind of) specialization of the previous PP supports functional-like programming (without memory leasks) with a language that does not rely on a garbage collector (e.g. with C, unlike Java or JS which have such a garbage collector): with such a language, a function shoud not allocate memory for returning an object, it should instead initialize or modify its last parameter and return it. Thus, the stack can be used (by a calling function) instead of the heap (by a called function). Although memory allocation is not considered as a side effect for functional programming purposes, it can be seen as a kind of side effect and then this last PP can more easily be seen as a specialization of the previous one.
PP_2.2.5.2: never directly allocating (and de-allocating) memory (e.g., using "new" or "mallow" (and "delete" or "free") but using

PP_2.2.6: mainly using the InterCap/CamelCase naming style (for functions and variables) since it is concise and allows the separators "_" and "__" to have special meanings (see the following PPs; note: in most programming languages, identifiers characters can only be 'a'..'z', 'A'..'Z','0'..'9' and '_', so '-' is generally not a usable character, only '_' is).

PP_2.2.7: using a “method naming convention” that indicates at least the following information, in that order (and in a distinguishable way, e.g., separated by “_”, “__” or “___”;  note: if “_” is used as delimiter within one of the following pieces of information, e.g. the 3rd or 5th one in the following list, “_” cannot be used as delimiter between the pieces of information, “__” or “___” can be used instead):

  1. if the method is a class method (hence not an "object member method"), an indication that it is, e.g. via the prefix "cl" (as in "cl_restOfTheNameOfThisClassMethod"), "_mk" or "mk";
  2. if the method is asynchronous (e.g. is a co-routine or can be lazily-evaluated), an indication of which kind, e.g. "gener" for a generator, "task" for a task, "thread" for a thread, and, more generally, "async" for an "asynchronous evaluation" and/or "deferrable" for a "lazy evaluation";
    the "parallel execution policies may also be made explicit via keywords such as "seq" ("sequentially"), "par" ("parallel") and "parUnseq" ("parallel unsequenced");
  3. if the class/object method is not about the whole class/object but about a sub-object/attribute of it, an indication about the type of this sub-object/attribute, e.g. “char” (vs. “str”) if the method is about retrieving or modifying a character; (vs. sub-string) in a whole string;
  4. the (kind of) performed operation, e.g. via the following names/prefixes,
    • for make/get/generate-from methods that do not modify the object:
      - “mk” (alias “make”, “create”), “mkTo” (or simply “to”);
        if “mk” is not followed by a class name, the kind of class is the same as the one of the method;
      - “indexOf”,   “at” (alias “getAtIndex”);  “nb” (alias “getNbOccurrencesOf”);
      - “cpSetAt” (alias “iSetAt” or “immutableSetAt”);
      - “cpReplEach” (alias “iReplEach” or “immutableReplaceEachOccurrenceOf”);
      - “cpAppend” (alias “copyAndAppend”, “immutableAppend”);
      - “cpDelAt” (alias “copyAndDeleteAt”, “immutableDelAt”);
    • for set/transform/delete methods:
      - “setAt” (alias “mutableSetAt” or “mSetAt”);
      - “setAppend (alias “addAtEnd” or “mAddAtEnd”);
      - “replAt” (alias “mReplAt”), “repl” (alias “replBy” or simply “mv”);
      - “delAt” (alias “rmAt”), “setDelLast” (alias “rmLastOccurrenceOf”);
    • test methods begin by “is” (or “are”) or “has” (or “are”) or “if”.
  5. the (kind of) each additional important mandatory parameter
    (thus, the kind of return value may also by specified at the end).

Box 1: Examples of Function Normalization. Here are examples of normalized names for methods from Javascript classes such as Number, String, Array and Object. (The main constructors of these classes are not included in the list below since they have the name of these classes and hence are already normalized.) The parameter descriptions used in the pointed Web sites for the three classes are kept. These normalization examples show that the used conventions lead to i) giving more precision, ii) making similar functions have more similar names, and iii) making explicit distinctions between similarly named functions (e.g. see the methods named “entries”).
The methods listed below, on the right, also sometimes generate exceptions (here is the list of their types; as implied by PP_2.1.1.3, in Systematic Functional defensive programming (SFDP), the methods normalizing/encapsulating the methods listed below, on the right, should catch these exceptions and return an adequate error value).

      Method name in Javascript                                 Normalized name
                                Construct(-this-(from)) / MkIterator / Iterate / Call
       (regarding the returned value type, see the prefixes in Box 2, the next 2 rows and the comments)
----------------------------------- Construct:
Number.parseInt(str,[radix])                     Number.mkIntFromStr(str,[radix])       //"mkInt"->int returned
Math.abs/cos/exp/...(number)                     Math.numAbs/numCos/numExp/...(number)  //"num" -> Number
Date.now/parse/UTC()                             Date.cl_now/parse/UTC()                   //no prefix -> Date
BigInt.asIntN(width,bigint)                      BigInt.mkWith(width,bigint) //idem for asUintN
Object.create(proto,[ObjProperties])             Object.mkFromPrototype(proto,[ObjProperties])
Object.fromEntries(iterable)                     Object.mkFromIterable(iterable)        //no prefix -> Object
Object.entries(obj)                              Array.keyValuePair_mkArray(obj)        //"mkArray" -> Array
Number.parseInt(str,[radix])                     Number.mkIntFromStr(str,[radix])       //"mkInt" -> int(eger)
Object.keys(obj)                                 Object.key_mkArray(obj)  //icpadem for values
Object.getOwnPropertyNames(obj)                  Object.nonInheritedProperty_mkStrArray(obj)
String.fromCharCode(num1[,...[, numN]])          String.mkFromUTF16codes(num1[,...[, numN]])
String.fromCodePoint(num1[,...[, numN]])         String.mkFromCodePoints(num1[,...[, numN]])
Array.from(arrayLike[,mapFn[,thisArg]])          Array.mkByCp1stLevelOf(arrayLike[,mapFn[,thisArg]])
Array.of(elem0[,elem1[,...[,elemN]]])            Array.mkWith(elem0[,elem1[,...[,elemN]]])
----------------------------------- MkIterator:
Array.keys()                                     Array.key_mkIterator()    //idem for values
Array.entries()                                  Array.keyValuePair_mkIterator() 
----------------------------------- Iterate:
Array.some(fct[,thisArg])                        Array.isForSome(fct[,thisArg]) //"is" -> boolean
Array.every(fct[,thisArg])                       Array.isForEach(fct[,thisArg])
Array.forEach(fct[,thisArg])                     Array.doOnEach(fct[,thisArg]) //this method may modify the array!
Array.reduce(fct[,thisArg])                      Array.aggregateFromEach|reduce(fct[,thisArg]) //(no modif)
Array.reduceRight(fct[,thisArg])                 Array.aggregateFromEachFromEnd(fct[,thisArg]) //|fold|raccumulate
Array.map(fct[,thisArg])                         Array.cpDoOnEach|map(fct[,thisArg])
Array.flatMap(fct[,thisArg])                     Array.cpDoOnEachThenFlat|mapThenFlat(fct[,thisArg])
Array.filter(fct[,thisArg])                      Array.cpDoOnEachSatisfying(fct[,thisArg])
Array.find(fct[,thisArg])                        Array.at1stSatisfying(fct[,thisArg])
Array.findIndex(fct[,thisArg])                   Array.indexOf1stSatisfying(fct[,thisArg])
----------------------------------- Call:
Fct.call(thisArg[, arg1, arg2, ...argN] )        Fct.callWithArgs(thisArg,[argsArray])
Fct.apply(thisArg,[argsArray])                   Fct.callWithArgArray(thisArg,[argsArray])
Fct.bind(thisArg,[argsArray])                    Fct.mk(thisArg,[argsArray]) 
                                        Test (the returned value type is a boolean/integer/...)
              (same prefixes as in the next "box"; e.g.,  for booleans: "is", "has", "do", ...)
Number.isNaN/isFinite/is(Safe)Integer(value)     Number.cl_isNaN/...(value)
Array.isArray(value)                             Array.cl_isArray(value)
Object.is(value1,value2)                         Object.cl_areIdentical(value1,value2)
String.includes(searchString[,position])         String.substr_isAt(searchString[,position])
Array.includes(valueToFind[,fromIndex])          Array.subArr_isAt(valueToFind[,fromIndex])
String.startsWith(searchString[,length])         String.isStartingWith(searchString[,length])
String.endsWith(searchString[,length])           String.isEndingWith(searchString[,length])
String.localeCompare(compareString[,locale])     String.iNumForDiff_inLocale(compareString[,locale])
                                        Get-from / Generate-from(toString,toPrint,...,cpAppend,cpReplace,...)
  (the returned value type is either explicit from the selected part and/or action, or is the same as the class)
----------------------------------- Get-from  
String.charAt(index)                             String.char_at(index)
String.charCodeAt(index)                         String.char_at_inUTF16(index)
String.indexOf(searchValue[,fromIndex])          String.substr_index(searchValue[,fromIndex])
Array.indexOf(searchElement[,fromIndex])         Array.subArr_index(searchElement[,fromIndex])
String.lastIndexOf(searchValue[,fromIndex])      String.substr_lastIndex(searchValue[,fromIndex])
Array.lastIndexOf(searchElement[,fromIndex])     Array.substr_lastIndex(searchElement[,fromIndex])
String.search(regexp)                            String.substr_index(regexp)
String.slice(fromIndex[,toIndex])                String.substr_cpAt(fromIndex[,toIndex])
Array.slice(fromIndex[,toIndex])                 Array.subArr_cp1stLevelAt(fromIndex[,toIndex])
String.substr(fromIndex[,length])                String.substr_cpAt(fromIndex[,length])
String.substring(fromIndex[,toIndex])            String.substr_cpAt(fromIndex[,toIndex])
AA_VarValue.sVar__pxValue_toString(const char*)  AA_VarValue.sVar__pxValue(const char*)//->T*
----------------------------------- Generate-from (last: the cpAndModify):  
Date.getDate/getTime/toJSON...()                 Date.toIntDate/toIntTime/toJSON...() 
Number/BigInt/Boolean.valueOf()                  Number/BigInt/Boolean.toValue() 
BigInt/Number/Fct/Array.toString()               Array/....toString() //so, toString and toPrint should exist or
                  Array.join([separator])        Array.toStrWith[separator])      //  be automatically derivable
BigInt/Number/Array.toLocaleString([loc[,opts]]) Array/....toLocaleString([locales[,options]])
       Number.toPrecision/toExponential/toFixed  Number.toStrWithPrecision/...
Array.flat([depth])                              Array.cpFlattenedTill([depth])
String.split([separator[,limit]])                String.cpSplit__strArray([separator[,limit]])
String.concat(str2[,...strN])                    String.cpAppend(str2[, ...strN])
Array.concat([value1[,...valueN]])               Array.cpAppend([value1[,...valueN]])
String.repeat(count)                             String.cpAppendNtimesToItsef(count) 
String.padEnd(targetLength[,padString])          String.cpAppendPaddingIfNeededToReach(targetLength[,padString])
String.padStart(targetLength[,padString])        String.cpPrependPaddingIfNeededToReach(targetLength[,padString])
String.normalize([form])                         String.cpReplEachCharByItsUnicodeNormalizedValue([form])
String.toLocaleLowerCase([locale,...])           String.cpReplEachCharByItsLowerCaseInLocale([locale,...])
String.match(regexp)                             String.toArrayOfStringsMatching(regexp)
String.matchAll(regexp)                          String.toIteratorForStringsMatching(regexp)
String.replace(regexp|substr,newSubstr|fct)      String.cpReplace1st(substr,newSubstr|fct)
                                                 String.cpReplace(regexp,newSubstr|fct)
String.replaceAll(regexp|substr,newSubstr|fct)   String.cpReplaceAll(regexp|substr,newSubstr|fct)
String.trim()                                    String.cpDelWhiteSpacesAtBeginningAndEnd()
Array.copyWithin(target[,start[,end]])           Array.cpReplaceAt1stLevel(target[,start[,end]])
                                        Set / Replace / Delete   ('m' prefix: “modify”, alias “mutate”)
 (the returned value is (a pointer to) the one of the set/replaced/deleted element; null/NULL if error)
----------------------------------- Set:
Date.setDate/setTime/...()                       Date.setWithIntDate/setWithIntTime/...()
----------------------------------- Replace:
Array.fill(value[,start[,end]])                  Array.setEachElemTo(value[,start[,end]])
Array.unshift(element1[,...[,elementN]]))        Array.mPrepend()
Array.push([element1[, ...[, elementN]]])        Array.mAppend([element1[, ...[, elementN]]])
Array.reverse()                                  Array.mReverse()
Array.sort([compareFunction])                    Array.mSort([compareFunction])
Array.splice(start[,delCount[,item1[,...]]])     Array.elems_setOrDel(start[,delCount[,item1[,...]]])
AA_VarValue.sVar_pxValue_addOrUpdate(const char*,const char*)
----------------------------------- Delete:
Array.shift()                                    Array.firstElem_del()
Array.pop()                                      Array.lastElem_del()


PP_2.2.8: (in accordance with PP_2.2.6 and the O.O. based approach advocated by PP_2.2.1) naming “pseudo-methods” by

Functions that do not include '_' (hence that do not begin by a class name) should begin by a lowercase letter. The name of a macro for a function should not include '_'. Thus, function names without '_' and with an uppercase initial should be macros.

2.3. Variable Names
(PP_2.3: using good/useful variable names, essentially, informative ones, even if long)

Reasonably long names (→ typically less than 40 characters long) can be used in ways that do not strongly reduce the readability of a program and, the more information are stored in variable names (e.g. about their types), the more useful these name are. Using conventions (or a formal language) when storing information in a name make some of the information extractable and exploitable via a software (e.g., for checking and translation purposes): the name is then said to be semi-formal. The more conventions are used (or, the more a formal language is used), the more information can be stored in an automatically exploitable way. A knowledge representation language can be designed and used for representing information within a name (-> some of its meaning) but i) this often lead the name to be quite long and/or hard to read for people, and ii) a KB system must be used to decode and exploit the information (→ an heavyweight solution that is generally not required for programming purposes only). Using conventions such as the ones presented below is a good tradeoff: although using some of these conventions slightly reduces readability for people that do not know these conventions, it may be argued that the more such conventions are used in a name, the more useful the name (hence the better).

PP_2.3.1: using very informative names (PP_2.1.1.1) for variables and hence, generally, long names and NO abbreviations (except for an abbreviation that is frequently used AND whose meaning has been made explicit via a document referred to in the program header, as for the reserved prefixes of PP_2.3.4).

PP_2.3.2: when naming variables, using uppercase characters in the following ways (which are classic in C programs):

Note: in most programming languages, identifiers characters can (unfortunately) only be 'a'..'z', 'A'..'Z','0'..'9' and '_'; thus, '-' is generally not a character usable within names, only '_' is.

PP_2.3.3: when naming variables, using the separator "_" when the InterCap/CamelCase naming style is insufficient, e.g. for specifying the following kinds of information (in that order):

PP_2.3.4: using prefixes in each variable name (or, '_' separated variable name part that specifies a member/property/sub-element) for indicating the type of this variable (or part) (for the reader to know this type without having to re-access – or memorize – variable declarations). The ending of a prefix may be the ending of the name, a number, a '_' or “an uppercase characters after some lowercase characters”. Whether a typed language is used or not, i.e. whether types are also formally declared or not, using such prefixes eases the understanding of the code. When the used language is not typed, using such prefixes often avoid having to use comments (e.g. comments directly or indirectly specifying types of variables).
This PP is not contradictory with PP_2.1.2.1 (not directly relying on particular data types/structures), as explained in the above description of that PP. It should also be noted that using data structures that represent generic "knowledge representations" is ideal for genericity and interoperability purposes.
The following box contains a list of useful prefixes (if the programmer use other ones, they should be listed in the program header or in a document referred to in the program header).

Box 2: List of Prefix Examples For Common Types. Below, various prefixes are proposed for various types of objects and these types are organized into an indented list that show their subtype relations. When type names from Javascript (JS), C or C++ could be reused below, they are: they are within single quotes ('...'), JS/C++ class names have an uppercase initial, C type names have a lowercase initial (except for 'FILE'). The other type names are whithin double quotes ("..."). The type names in bold characters are the JS types reused in JSON and JSON-LD.
Prefixes for the most precise types should be used (hence, for example, the prefix "num" should not be used if the prefix "int" can be used).

"Anything" (any information object, whichever their type): "x",   "e","elem"(collection item)

   "PrimitiveObject" (object of a basic/built-in data type): "builtin"
      'Symbol': "symbol", "symb"           "type" (type)
      "PrimitiveValue" (literal or not, e.g. a Primitive in JS): "v", "val", "value"
         'Number': "n", "nr"  //but "nb" ("uint") and "num" ("usize") are for Naturals; see below 
                   "nru" (unsigned, i.e. >=0), "nrp" (positive: >0), 
                   "nr32"|"nr4b"|"fl" ('float': floating-point number of at least 32 bits (3 bytes))
                   "nr64"|"n8b"|"d"  ('double': floating-point number of at least 64 bits (8 bytes))
                   "dl" ('long double': generally 10 to 12 bytes; see en.cppreference.com/w/cpp/language/types)
                   "n64u" (unsigned n64), "flp" (positive float)
            'int': "zi", "int" (16 or 32 bits on a 32-bit system), "szi" (short int: 16 bits)
                   "zil"  ('long int': n bits on a n-bit system)
                   "zill" ('long long int': 64 bits on a 32/64-bit system)
                   "zib"  (JS BigInt: used in JS to represent arbitrary large integer, those  253)
               "enum": "enum"  (e.g. std::byte) or as for int/uint/...
               "int>=-1": "i" (to follow by a number; do not use "j", "k"),  "index",
                          "lastIndex", "fromIndex", "toIndex" (esp. for Get-from/Generate-from fcts)
                 'size-t' ("usize"): "zu", "num", "size", "lng", "length", "uIndex", "uindex", "depth"
                                         //note: these prefixes may be preceded by "min" or "max"
                   'uint' ("natural"): "ui", "uint", "nb"
                     "nb16"|"nb2b" (natural on 4 bytes),  "nb32"|"nb4b" (natural on 4 bytes)
                     "natural>0": "nbp", "ip"  (cf. prefixes 'p' and 'u' and 'nr' above)
                        'byte' ([0 to 255]): "uc", "ui1b" //since "cu" is for "update cursor"  (see below)

                           "Truth-value/Boolean-like" ('bool', O12, O123): "b", "b012" "b0123",
                               "with", "has", "is", "are", "can", "may", "must", "no", "do", "use",
                               "for", "in", "equal", "caseEqual", "only"
                  'char': "c", "char",  "cz" ([-127 to 127]),  "uc" ([0 to 255]),  "cs1" (string of length 1, as in JS)

   "NonPrimitiveObject" (object of composite type or abstract data type, e.g. a "JS Object"): "o", "obj",
                       "k" (knowledge representation object), "ko"
                       //immutability (read-only) (if not the default option) may also be specified (e.g. "or") and used
                       //  since it allows safer, simpler and sometimes quicker functions; see also this in C++
      'union': "u"  //except for "uc" ("unsigned char") 
      'Function': "fct", "f"   //see Box 1 (above)
      'FILE': "fi",  "fp" (file pointer, "pof" is also ok)  //but "ifd": int "file descriptor"; see std::filesystem too)
      "ReferenceObject"
         "AtomicReference": "p" (object that is an in-memory pointer or would be if translated in C++),
                            "rp" (object that is a C++ reference or would be if translated in C++),
                            "rpr" (read-only "rp", i.e. the value cannot change), "rpro" (const "rp" on an object) 
         "IdReferenceObj" (-> id/key or mainly including that): "r", ro", "rid"  //but "StringIdForAnObject": "sid"
         "Iterator" (function/pointer/... to traverse a collection, e.g. std::iterator)
            "Cursor" (to traverse/point to an object/collection, esp. in a DB): "cur",
                                                                    "cu"(read cursor), "cu"(update cursor)
      "Collection" (e.g. C++ container):  "coll",  "collv" (for a "view": collection of items/references, each removed
                                          when what is pointed to is removed (e.g. garbage collected), e.g. std::span);
                                          all collections are or can be iterable (not "enumerable")
         "Sequence": "seq", "stack" (std::stack), "queue" (std::queue), "queueWpriority" (std::priority_queue")
            "List" (non-numerically indexed sequence): "list", "lst", "li"
               "SingleLinkedList" (forward-only, e.g. std::forward_list): "lif"
               "DoubleLinkedList" (forward+backward, e.g. std::list): "lifb",  "lifbqueue" (std::deque)
            'Array' (-> numerically indexed): "a", "ar", "arr", "subArr", "table"
                                              "as" (static: fixed-size), "ad" (dynamic, hence a "vector")
                                              "ab" (array/view for a blob, i.e. for a binary large object)
                                              "aspan" (span: view on an interval on another array)
               "ArrayOfHeterogeneousValues"
                  "Tuple" (fixed-size, e.g. std::tuple, std::pair): "tup", "tuple", "pair", "triple"
               "ArrayOfHomogeneousValues" (e.g. std:array, std::vector)
                  "NullTerminatedArray": "a0" ("sc" or "sa" if C-like string)
                  "StringOrCharPointer": "s"/"str" (<=> "sc" in a C program, "dstr"/"string" in a JS program, ...),
                                         ("1st"/"2nd"/...)("sub")("str"/"name"/"word"/"w"/"text"/"token"),
                                         "to"("Locale")("String"/"Print") (for Get-from/Generate-from fcts)
                     "Cstring": "sc" (non-allocated C-like string pointer), "sa" (allocated C-like char array)
                     'String' (dynamic; with a size/length attribute): "ds", "dstr", "string"
                        "StringView" (e.g. std::string_view): "strv"
         "KeyedCollection"
            "Multimap" (associative array that may store the same key several times, e.g. C++ std::map): "mapm"
               'Map' (e.g. C++ std::map): "aa",  "aah" (map based on an hash-table)
                  "MapView" (or 'WeakMap') : "aav" (stores 'key/referenceToValue' items; see "view" above) 
            "Multiset" ("Bag", e.g. C++ std::multiset): "setm", "bag",  "bagh" (bag based on an hash-table)
               'Set' (e.g. C++ std::set): "set",  "seth" (set based on an hash-table)
                  "SetView" (or 'WeakSet'): "setv" (stores 'referenceToValue's; see "view" above)
         "Graph": "graph"
            "Tree" (connected acyclic graph; generally "undirected" in math and directed in data structures): "tree"
               "Heap" (std:make_heap): "heap"

2.4. Other Names: File Names, XML Names, ...

PP_2.4.1: using the same conventions for file names as for variable names (cf. previous subsection; → only using a-z, A-Z, 0-9, '_' and '-', hence not using spaces and accentuated character; this eases the retrieval and handling of file name via scripts) and beginning non-directory file names by a lowercase character.

PP_2.4.2: using the same conventions for markup names as for variable names (cf. previous subsection) and, for individuals (types instances that are not types, e.g. HTML form element identifiers), prefix/suffix them with an abbreviation of their types. Here are examples of prefixes/suffixes:

Examples of their use: “addressInput”, “passwordInput”, “transmissionChoice”.

2.5. About Documentations

PP_2.5.1: for each file, giving at least the following information in its header, via comments and/or using more formal ways:
- creator: name, identifier+contacts (URL, e-mail, ...);
- creation date;
- purpose of the content of the file and what remains to be done wrt. this purpose;
- ways to use or test the file, e.g. description of its inputs and outpouts (e.g. parameters, identifiers of input/test files) if it has some;
- ways the content has been tested/validated.

For the header of a program, here is an example variant of the first kind of line:
/* in this text editor, this comment is currently as large as 83 characters outside comments */

2.6. About Inputs and Outputs: User Interfaces, ...

PP_2.6.1: distinguishing the content, structure and presentation of information, as well as their handlings, and letting the user choose or parameter these 3 aspects and their handlings, while not forcing the user to make choices nor (re-)enter information (thus, this PP specializes PP_1.1). Furthermore, what can be decentralized on the user's machine should be (PP_2.1.4.4) and, more generally, all the media/devices/... that can be exploited should be (PP_1.2.2). Example sub-PPs:

3. Non-Structural/Lexical PPs (→ Programming Style)

3.1. Size/Space/Indentation Related PPs

PP_3.1.1: using a compact style (→ concision when this does not conflict with explicitness; this presentation PP has no consequence on structural/lexical PPs and hence on the length of function/variable names for which PPs where given in Section 2.2 and Section 2.3). Since the short-term memory of most people is very limited, functions should be as short as possible for people to see as much of them without scrolling and thus understand and compare them easily. In other words, the more code the reader can see and compare at a glance (i.e., without scrolling), the better. If scrolling is necessary, debugging or reuse time is greatly increased.
Here is an example sub-PP:

PP_3.1.2: using lines of no more than
79 characters if this does not make the code harder to read,
– 83 characters for lines that do not include any comment, and
– 95 characters otherwise.

Indeed, lines should remain readable – hence without line wrapping or the use of an horizontal scroll bar – wherever/however it may commonly be displayed, e.g., on a small screen, or using a 12-point, or in a pure text e-mail (in such emails, lines over 79 characters are often automatically line wrapped; gmail wraps at 70 characters or sometimes till 83 characters if a word has begun before the 70-character limit; here are some notes on the optimal line length for non-code text).
PP_2.5.1 shows how the program header can be adapted to ease complying with such a PP.

PP_3.1.3: using a space after the function name in its definition, never when in its calls (this eases lexical searches of function definitions in programs with many modules).

PP_3.1.4: aligning block delimiters, e.g. the '{' '}' brackets, vertically or horizontally, e.g, as in the GNU style. This is a specialization of the Horstmann style (it is equivalent to the Allman style – alias BSD style – when the '{' is alone on a line, which is to avoid since this is a useless loss of space). However, there is no need to indent the direct sub-elements of the HTML tag (e.g., HEAD and BODY) nor their direct sub-elements (e.g., STYLE, SCRIPT, P, H1 ...H5).
Note: other styles for curly braces are less symmetric and hence less readable (← less helpful to find block delimiters) but this is a matter of taste and there is no information loss is using one style or another since they can all be automaticaly generated.

PP_3.1.5: within an If-Then-Else statement, putting the smaller block first.

PP_3.1.6: when '=' is the operator for assignments, not using 1 space before, i.e. writting them as in "i= 1;" or "i=1;", never like "i  =  1;", since this wastes space and ressembles too much equality tests ("i==1"). When an assignment is used within a test (as in “if ((n= 2)) then ” or “if (!(n= 2)) then ”), put a space after the '=' and use two sets of parenthesis. C/C++ compilers enforce this.

PP_3.1.7: using 1 space before and after a single '=' used for an equality test.



Box 3: Example 1 About Indentations. Comparaison of two ways of indenting a same function.
The left one is clearly better for readability or understanding purposes but still has 7 kinds of
presentation problems (4 regarding indentation/spacing) wrt. the above listed PPs.


Box 4: Example 2 About Indentations. Case-by-case examples using the Javascript syntax.
The bad/good "if" examples are also bad/good examples for any other kind of block: "while", "for",
"function", "<td>", etc.

BAD BETTER (for above cited reasons/criteria)
prErr ("...");
prErr("...");
function someFct() 
function someFct ()
a = 1;
a= 1;
if(a==1) ...
if (a==1) ...
if (a = b) ...
if ((a= b)) ...
if (!(a)) ...
if (!a) ...
if (a) { a= b; }
if (a) a= b;
if (a){a=b; b=2;}
if (a) { a= b;  b= 2; }
if (a) {
  a= b;  ...
}
if (a)
{ a= b;  ...
}
if (a)
{
a= b;  ...
}
if (a)
{ a= b;  ... 
}
if (a)
{
  a= b;  ...
}
if (a)
{ a= b;  ...
}
if (a)
{a= b; 
 c= d;
}
if (a)
{ a= b;
  c= d;
}
if (a)
   { a= b;  ...
   }
if (a)
{ a= b;  ...
}
if (a)
{ a= b;
     if (b) ...
}
if (a)
{ a= b;
  if (b) ...
}
if (a)
{  a= b;
}
if (a)
{ a= b;
}
function someFct1 ()//...   
{ ...
}
function someFct2 ()  //...   
{ ...
}
function someFct1 ()  //...   
{ ...
}

function someFct2 ()  //...   
{ ...
}

function someFct(someNumber) {       

  if(result = someNumber + 1) {
    prErr ('Some error message');
    return result;
  }
  if(someNumber ==0)
   { result = 1; }
  return result;
}

/*int*/function someFct (/*int*/someNumber)
{ /*int*/result= 0;
  if (someNumber==0) result= 1;
  else if ((result= someNumber + 1))
  { prErr('Some error message');
    return result;
  }
  return result;
}

sub someSubroutineName
dim a
a = 8
while a > 1 
a = a - 1
end while
end sub

sub someSubroutineName 
  dim a
  a= 8
  while a > 1 
    a= a - 1
  end while
end sub
<table>
<tr><td>cell 1</td>
<td>cell 2</td>
</tr>
</table>
<table>
  <tr><td>cell 1</td>
      <td>cell 2</td>
  </tr>
</table>