The Universal Function Library Project

Introduction

The UFL, Universal Function Library, is a set of around 100-300 standard functions for all programming languages. Languages do not have to implement anything exactly to the UFL specification, it is a guide. In addition, a small number of recommendations are made regarding operators and statements. See below. Furthermore, some recommendations regarding specific programming languages are made. See below.

General Recommendations: Operators and Statements

All programming languages should have the following: a standard ternary operator (use alternative symbols if '?' and ':' aren't available): c ? x : y [C uses c ? x : y][Raku uses c ?? x !! y][perhaps c ??? x : y][perhaps c ??? x ::: y] a short ternary operator (a 'falsy-coalescing operator') x ?: y [PHP uses x ?: y][JavaScript uses x || y][equivalent to x ? x : y] a swap statement or function: swap var1 var2 Swap(&var1, &var2) [Swift uses swap(&a, &b)][C++ uses std::swap(a, b)] a noop statement or function: noop [Python uses pass] Noop() 2 mod operators: a % b [C-style (truncated) mod][C uses %][more common, but less useful: for positive b, the return value is positive, 0 or negative (depending on the sign of a)] a %% b [floor mod][R uses %%][Python uses %][more useful: for positive b, the return value is always positive or 0] 3 integer division operators for integers and floats: a / b [true divide][returns a float][use an alternative symbol if / does C-style (truncated) integer division][returning a float is more intuitive, and pretty common (e.g. JavaScript/PHP/Python)][truncating the return value breaks the principle of least astonishment, and often leads to bugs] a ~/ b [C-style (truncated) integer divide][Dart uses ~/] a ~~/ b [floor divide][Python uses //][perhaps ~//][perhaps _/][there may be a better symbol than ~~/] See the relevant pages for more details: Programming Language Comparison: General (Control Flow/Debugging) Programming Language Comparison: Operators and Symbols

General Recommendations: Functions and Methods

common debugging functions: ● Print: a good variable print function, either the main print function, or an additional function, that can display the contents of primitives/strings/arrays/maps etc (full depth by default, perhaps with a depth parameter) (appends linefeed by default) ● Type: succinct 'get variable type' functions, that work on all variables (perhaps 2 versions, short name, and full name) ● Version/LangVersion: a well-thought out, version number function, to report the programming language version number, the one function that must be designed right first time (e.g. it just returns a friendly string e.g. '1.2.3.4', or it returns an object, where one member is a friendly string) (new version functions may be added, but old version functions must not be removed/modified to be backwards incompatible) key string functions that should be more widespread: ● StrStarts/StrEnds ('StrStartsWith'/'StrEndsWith') (avoids verbosity and arithmetic errors with string slicing, makes the intention clear) ● ... in addition, StrContains ('StrIncludes'), is shorter, more readable and more intuitive than (StrIndexOf() != -1) ● ... and to complete the set, StrEquals, is more intuitive than !StrCompare() and allows for a case-sensitivity parameter, unlike 'str1 == str2' ● StrCount (PHP uses substr_count, Python uses str.count), e.g. do a line count, useful in algorithms ● StrRept (JavaScript uses repeat, PHP uses str_repeat), e.g. indent text, useful in speed tests, useful in unit tests and demo scripts, useful in algorithms ● SubStr/StrSlice: languages should have both of: SubStr (pos/length) and StrSlice (pos1/pos2) key mathematical functions that should be more widespread: ● FloorMod (extremely useful) ● Sign/Clamp (they make the intention clearer, avoid bugs, and can be useful for writing readable one-liners) ● VerCompare/IPCompare (compare version numbers/IP addresses, return negative/0/positive) ● PopCount (useful for algorithms, and useful for tight loops where speed matters) ● MRound (round to the nearest multiple of n) ● Combin/Permut ● Gamma ● Erf ● Between ● Round/RoundEven ('round' in different languages, some round tiebreakers away from 0, some use bankers' rounding, for simplicity, make both available) ● RandomInt (random int between a inclusive and b inclusive (or b exclusive), the lack of such functionality makes random number generation: verbose, less readable, sometimes biased, and sometimes at risk of throwing) ● RandomFloat (random float between 0 inclusive and 1 exclusive, the lack of such functionality makes random number generation: verbose, less readable, sometimes biased, and sometimes at risk of throwing) ● DecToBase/BaseToDec (int-to-string/string-to-int conversions for bases 2-36, 2/8/10/16 are the common ones, but the rest are useful for algorithms) key type-agnostic functions that should be more widespread: ● CompareTo or <=>, a function that compares 2 values using the default comparator, useful for concise custom sort comparator functions (failing that, at least NumCompare/StrCompare functions) key general functions that should be more widespread: ● Exit (similar to PHP's 'die', a function that unconditionally exits, for convenient debugging / code experimenting and for security) See the relevant pages for more details: Programming Language Comparison: Strings Programming Language Comparison: Mathematics Programming Language Comparison: Dates Programming Language Comparison: Objects

General Recommendations: Syntax

key syntax that requires very careful consideration: ● modules (e.g. handle: modules have names and version numbers) (e.g. handle: include this module, unless a newer version of a module with the same name exists) ● requires (e.g. handle: requires version range 1.0<=x<1.5 || 1.6<=x<2.0, i.e. specify gaps e.g. exclude 1.5.x.x) (e.g. handle: requires range 1.0<=x<1.5 || 2.0<=x<2.5, i.e. allow the first integer to differ) (see also: Version/LangVersion) ● #if directive or equivalent (e.g. using the logic mentioned for 'requires', include a code block, if the programming language version number matches the specified version range)

Specific Language Recommendations

AutoHotkey: ● add Array methods: Sort/Reverse/(Swap), Join, IndexOf/LastIndexOf, (FirstOrDefault)/(FirstIndex), (Flat), (IsDense) ● add Array methods with a 'WithIndex' option: Map/Reduce/(ReduceRight)/Filter, GroupBy, (Count), (All)/(Any)/(None) ● add a Range object C++: ● add a short-ternary operator (Elvis operator) or Or() function (e.g. 'a ?: b') (equivalent to 'a || b' in JavaScript, 'a ?: b' in PHP, and 'cmp.Or(a, b, ...)' in Go) that returns the first truthy value or the last falsy value, rather than a boolean) ● add some form of Array.Join() (that can at least handle string/integer/float values) ● add an insertion-order map (dictionary) ● std::accumulate (i.e. reduce): allow omitting the seed (init) value, i.e. the first value is the seed ● int to string 'dec to base' conversion (like itoa) (std::stoi already does 'base to dec') ● (add an insertion-order set) (ordered set) C#: ● make dec to/from base conversions possible for all bases 2-36 (Convert.ToString/Convert.ToInt32 only handle bases 2/8/10/16) ● add a short-ternary operator (Elvis operator) or Or() function (e.g. 'a ?: b') (equivalent to 'a || b' in JavaScript, 'a ?: b' in PHP, and 'cmp.Or(a, b, ...)' in Go) that returns the first truthy value or the last falsy value, rather than a boolean) ● (add a spread operator for function calls) (note: awaiting confirmation: the '..' operator may fulfil this role in future) Crystal: ● multi-line comments Excel: ● add a sheet function to count string occurrences (working name: 'TEXTCOUNT') ● (add a bankers' rounding (round to even) function) Go: ● implement a standard ternary operator (use alternative symbols to ? and : if necessary, like Raku) (in Go, a ternary operator is currently a 5-liner, or a 6-liner if also declaring a variable) ● add a Range object ● add a Tuple object ● various built-in array/map functions (to reduce the need for mass code inspection where everyone rolls their own basic/semi-trivial functions, and to facilitate sharing/consistency/code reuse/performance) ● Go currently lacks both default function arguments and function overloading (without at least one of these, currently each function 'overload' needs a different name) Java: ● add a standard Round function (e.g. 1.5/0.5/-0.5/-1.5 etc should round away from zero) ● add computed object properties (i.e. 'obj.myprop = value' and 'value = obj.myprop' are currently available for standard properties, but not computed properties), the current workaround is to use getter/setter methods (e.g. 'obj.setmyprop(value)' and 'value = obj.getmyprop()') (some drawbacks: verbose to define, renaming a property requires 3 renames (private variable/getter/setter) in 2 places (parallel collections anti-pattern), usage: modifying a property is verbose e.g. incrementing: 'obj.myprop++' versus 'obj.setmyprop(obj.getmyprop()+1)') ● allow specifying default function parameter values (or some convenient/succinct alternative) ● add a short-ternary operator (Elvis operator) or Or() function (e.g. 'a ?: b') (equivalent to 'a || b' in JavaScript, 'a ?: b' in PHP, and 'cmp.Or(a, b, ...)' in Go) that returns the first truthy value or the last falsy value, rather than a boolean) ● add anonymous functions that work much like normal functions (one return type pattern (not 43), that can handle any number of parameters, that don't require (one of 11) special methods to call them) ● (add subscript/subscript-like syntax for maps/dictionaries) (the clunkiness of method syntax makes them off-putting to work with (e.g. getting/setting/incrementing/appending), and doesn't play well when working in multiple languages) ● (add a spread operator for function calls) ● (add C++-style pairs or similar) (note: this is/was a big debate, SimpleEntry may be sufficient) ● (add core set methods e.g. Diff/SymDiff/Intersect/Union) JavaScript: ● add a function for creating date strings from parts (e.g. AutoHotkey: FormatTime(d, "ddd yyyy-MM-dd HH:mm:ss"), e.g. Python: d.strftime("%a %Y-%m-%d %H:%M:%S %z")) ● add a function for creating strings from parts (e.g. AutoHotkey: Format("{:02}:{:02}:{:02}", 1, 2, 3), e.g. Python: "{:02d}:{:02d}:{:02d}".format(1, 2, 3)) (note: padStart is too verbose for use with multiple values simultaneously, and doesn't play well with negative numbers) ● (add subscript/subscript-like syntax for maps/dictionaries) (the clunkiness of method syntax makes them off-putting to work with (e.g. getting/setting/incrementing/appending), and doesn't play well when working in multiple languages) ● (add a function to return the variable's type, e.g. 'Array'/'Map'/'Object' rather than 'object') ● (add a bankers' rounding (round to even) function) Kotlin: ● add a standard Round function (e.g. 1.5/0.5/-0.5/-1.5 etc should round away from zero) ● implement a standard ternary operator (use alternative symbols to ? and : if necessary, like Raku) ● add a short-ternary operator (Elvis operator) or Or() function (e.g. 'a ?: b') (equivalent to 'a || b' in JavaScript, 'a ?: b' in PHP, and 'cmp.Or(a, b, ...)' in Go) that returns the first truthy value or the last falsy value, rather than a boolean) (confusingly, '?:' is already in use as a null-coalescing operator) ● (add square bracket syntax for defining arrays) ● (add subscript/subscript-like syntax for maps/dictionaries) (the clunkiness of method syntax makes them off-putting to work with (e.g. getting/setting/incrementing/appending), and doesn't play well when working in multiple languages) PHP: ● array_reduce: allow omitting the seed (init) value, i.e. the first value is the seed (at present, if the seed is omitted, null is used as the seed, not the first value) ● classes: __get/__set for static properties in some form ● (add a bankers' rounding (round to even) function) Python: ● add a string slice method (the unusual 's[i,j]' slice syntax, doesn't play well when working across multiple programming languages) ● implement a standard ternary operator (use alternative symbols to ? and : if necessary, like Raku) (particularly as it's such a mathematical language, it's frustrating that Python currently lacks this) (many languages that lack a ternary operator, at least have an alternative that uses the *same operand/parameter order* as a ternary operator, e.g. 'if (c) x else y' (Kotlin) and 'if c {x} else {y}' (Rust)) ● add && and || operators (clearer/easier to find than 'and'/'or') ('&&' is shorter than 'and') (also useful when working across multiple programming languages) ● add a join method to 'list' objects (that can at least handle string/integer/float values) ● partially reimplement the print statement ('print myvar'), to print strings/numbers/lists/dictionaries (useful for testing code when coding at speed, and to speed up the manual (non-automated) conversion of Python 2 scripts (by avoiding countless nags), and to avoid accidentally copying-and-pasting a trailing ')') (also, unlike Python 2, this could allow 'print myvar = 123', currently one must do 'print(myvar := 123)', but that requires refactoring, to use the walrus operator) ● add a string repeat method (the unusual 's * n'/'n * s' string repeat syntax, doesn't play well when working across multiple programming languages) ● int to string 'dec to base' conversion (int already does 'base to dec') ● multi-line comments ● classes: class property getters/setters (perhaps syntax similar to the existing decorators: '@classmethod'/'@property'/'@MyProp.setter') ● add a standard Round function (e.g. 1.5/0.5/-0.5/-1.5 etc should round away from zero) ● (more succinctly handle sort comparator functions that return negative/0/positive) ● (add an inclusive range function) (working name: 'rangeinc') ● (add a 'getOrDefault'/'getOrElse' method to 'list' objects for indexes that are out of bounds) (e.g. allow specifying a fallback value, or perhaps a fallback function, that receives the index and outputs a value) (without this, 1-liners become try/catch 4-liners) ● (add a 'rindex'/'lastindex' method to 'list' objects, i.e. a right-to-left version of 'index') ● (add an insertion-order set) (ordered set) R: ● multi-line comments ● int to string 'dec to base' conversion for bases 2-36 (strtoi already does 'base to dec') ● signed 64-bit integers (or big integers) ● add a standard Round function (e.g. 1.5/0.5/-0.5/-1.5 etc should round away from zero) Rust: ● implement a standard ternary operator (use alternative symbols to ? and : if necessary, like Raku) ● add an insertion-order dictionary (map) (e.g. as the default, as an option, or as a separate class) ● int to string 'dec to base' conversion (from_str_radix already does 'base to dec') ● Rust currently lacks both default function arguments and function overloading (without at least one of these, currently each function 'overload' needs a different name) ● (add computed object properties) (i.e. 'obj.myprop = value' and 'value = obj.myprop' are currently available for standard properties, but not computed properties) ● (add an insertion-order set) (ordered set) Scala: ● add a standard Round function (e.g. 1.5/0.5/-0.5/-1.5 etc should round away from zero) ● (add an insertion-order set) (ordered set) SQL: ● (some sort of 'reduce' syntax (e.g. get the product of a column) ('map' and 'filter' are already fundamental to SQL)) ● (a cross-compatible way to define a column, in a CREATE statement, that auto-increments each time a row is added) SQL (MySQL): ● == operator, for clearer code and better compatibility with SQLite (and other programming languages) ● FULL OUTER JOIN ● (add a 2nd optional param, char list as string, to trim/ltrim/rtrim) SQL (PostgreSQL): ● == operator, for clearer code and better compatibility with SQLite (and other programming languages) ● 'iif()' (SQLite) or 'if()' (MySQL) syntax, as a shorthand for '(CASE WHEN v1 THEN v2 ELSE v3 END)' SQL (SQLite): ● int to string 'dec to base' conversion for bases 2-36 ● string to int 'base to dec' conversion for bases 2-36 Swift: ● add a short-ternary operator (Elvis operator) or Or() function (e.g. 'a ?: b') (equivalent to 'a || b' in JavaScript, 'a ?: b' in PHP, and 'cmp.Or(a, b, ...)' in Go) that returns the first truthy value or the last falsy value, rather than a boolean) ● add an insertion-order dictionary (map) (e.g. as the default, as an option, or as a separate class) ● add a more succinct way to perform a string slice ● reduce: allow omitting the seed (init) value, i.e. the first value is the seed ● (more succinctly handle sort comparator functions that return negative/0/positive) ● (add a spread operator for function calls) ● (add an insertion-order set) (ordered set)