Languages usually provide features such as a type system, variables, and mechanisms for error handling.
While early programming languages were closely tied to the hardware, over time they have developed more abstraction to hide implementation details for greater simplicity.
These languages abstracted away the details of the hardware, instead being designed to express algorithms that could be understood more easily by humans.
For example, arithmetic expressions could now be written in symbolic notation and later translated into machine code that the hardware could execute.
[21] Unlike Fortran, it supported recursion and conditional expressions,[22] and it also introduced dynamic memory management on a heap and automatic garbage collection.
Although its commercial success was limited, most popular imperative languages—including C, Pascal, Ada, C++, Java, and C#—are directly or indirectly descended from ALGOL 60.
[27][16] Among its innovations adopted by later programming languages included greater portability and the first use of context-free, BNF grammar.
[28] Simula, the first language to support object-oriented programming (including subtypes, dynamic dispatch, and inheritance), also descends from ALGOL and achieved commercial success.
Its power and efficiency, generated in part with flexible pointer operations, comes at the cost of making it more difficult to write correct code.
[30][31] With logic programming, the programmer specifies a desired result and allows the interpreter to decide how to achieve it.
[38] Java, based on C++ and designed for increased portability across systems and security, enjoyed large-scale success because these features are essential for many Internet applications.
[39][40] Another development was that of dynamically typed scripting languages—Python, JavaScript, PHP, and Ruby—designed to quickly produce small programs that coordinate existing applications.
[43] One innovation was service-oriented programming, designed to exploit distributed systems whose components are connected by a network.
[54][55] Every programming language includes fundamental elements for describing data and the operations or transformations applied to them, such as adding two numbers or selecting an item from a collection.
Using natural language as an example, it may not be possible to assign a meaning to a grammatically correct sentence or the sentence may be false: The following C language fragment is syntactically correct, but performs operations that are not semantically defined (the operation *p >> 4 has no meaning for a value having a complex type and p->im is not defined because the value of p is the null pointer): If the type declaration on the first line were omitted, the program would trigger an error on the undefined variable p during compilation.
Languages that have constructs that allow the programmer to alter the behavior of the parser make syntax analysis an undecidable problem, and generally blur the distinction between parsing and execution.
Static semantics defines restrictions on the structure of valid texts that are hard or impossible to express in standard syntactic formalisms.
For example, the semantics may define the strategy by which expressions are evaluated to values, or the manner in which control structures conditionally execute statements.
Results from this field of research have seen limited application to programming language design and implementation outside academia.
Other languages define arrays as references to data stored elsewhere and support elements of varying types.
[69] Strings may be of fixed or variable length, which enables greater flexibility at the cost of increased storage space and more complexity.
Although this provides more flexibility to the programmer, it is at the cost of lower reliability and less ability for the programming language to check for errors.
[95] By the early 1960s, the idea of a universal language was rejected due to the differing requirements of the variety of purposes for which code was written.
[109] Increased expressivity due to a large number of operators makes writing code easier but comes at the cost of readability.
Edsger W. Dijkstra took the position that the use of a formal language is essential to prevent the introduction of meaningless constructs.
[117] Another implementation method is to run the program with an interpreter, which translates each line of software into machine code just before it executes.
Although it can make debugging easier, the downside of interpretation is that it runs 10 to 100 times slower than a compiled executable.
[125] Programming languages differ from most other forms of human expression in that they require a greater degree of precision and completeness.
When using a natural language to communicate with other people, human authors and speakers can be ambiguous and make small errors, and still expect their intent to be understood.
One language may occupy the greater number of programmer hours, a different one has more lines of code, and a third may consume the most CPU time.