Since the development of Plankalkül back in the 1940s, a large number of programming languages have been
designed and implemented – each for its own specific problem domains and made with its own set of design
decisions and compromises. For example, there are languages which:
• Are strongly typed and loosely typed,
• Provide support for object orientation / abstraction of data types,
• Use static or dynamic scoping rules,
• Provide memory management (i.e. garbage collection) or allow the developer fine-grained control
over heap-allocation and recycling,
• Provide closures to allow functions to be passed around like variables,
• Allow easy access to array slices and those which do not,
• Perform internal correctness checking of data and/or try/catch exception handling and those
which do not,
• Provide diverse and comprehensive suites of built-in functionality and those with a more limited set
of features,
• Use pre-processors and macros to selectively expand or substitute source code, etc.
Each of these decisions can have a profound effect on the usefulness of a programming language in terms of
factors such as its speed, robustness and general suitability to create programs of a certain type, such as for
operating systems, or in the areas of business, scientific computation, artificial intelligence or video games.