Some people believe that computers are constrained to only do what they were programmed to do. This is true only for the simplest programs. More advanced programs can also seek out new behavior that is not explicitly encoded in their source code. Complex behavior can emerge from simple rules. Let's see some examples starting from the most rigid programs and ending up in programs that are more than collections of rules.
Traditional software engineering solves problems by dividing them continuously into smaller and smaller steps until the steps are concrete enough to be expressed as program code. For example, a video player decompresses a video stream, extracts frames and displays them on a screen. Each of these stages consists of even smaller steps. There are certainly a lot of steps involved, but it is relatively clear what each step must do and how they are to be combined. Most software development is like this.
Some problems are, however, too complicated to yield to the traditional engineering approach. Examples include tasks such as recognizing objects in images or teaching a computer to play Go better than human champions.
Object recognition is difficult because the task doesn't decompose cleanly into simpler subtasks. A sensible sounding strategy would be to start by trying to detect elementary shapes in an image, but it is not clear what kind of shapes are helpful in describing objects. Moreover, even if one could decide what shapes to look for, combining detected shapes into an object description is a difficult task in itself. A round shape in a picture could be either a bicycle wheel or a pizza. The context is needed to determine the correct interpretation. If the surroundings in the picture contain shapes related to a typical street view, the round object might be a bicycle wheel; if the picture contains shapes related to a dinner table, the round shape is more likely to be a pizza. The correct interpretation of shapes depends on how other shapes are interpreted. This makes the recognition very complicated.
Tasks that do not decompose naturally are difficult to solve on a computer. Even if something is instinctively easy for humans, like object recognition, formalizing it as code can be infeasible. The standard way of modeling things by decomposing them into a hierarchy of smaller pieces is not possible if the hierarchy is too deep or if there are too many interdependencies within and across the hierarchy levels.
Complex problems like object recognition are usually attacked from an angle that differs from traditional software engineering. A computer is given plenty of example pictures of the objects it should learn to recognize. It will then search through possible algorithms that map an image into an object label. The intention is to find the algorithm that gives the most accurate results on the provided examples. This approach is called machine learning (or more exactly, supervised machine learning). It has seen a massive uptake in recent years in problems that are otherwise too complex to solve.
Machine learning is similar to traditional software engineering in the sense that they are both trying to solve a specific task. They differ in how a solution is found. The traditional approach relies on an engineer's ability to formulate a solution on a programming language. The machine learning approach depends on a computer to search for an algorithm that performs well on data. Machine learning is more flexible because it can find solutions even when only the goal is specified, but enumerating rules for every possible situation is infeasible.
Could we have even more flexible programs by abandoning the requirement to specify a goal? Surprisingly, removing the goal still leads to something interesting. Some systems exhibit self-organization where no one sets overall goals yet meaningful patterns emerge spontaneously.
Software ecosystems are examples of self-organization. Millions of developers are constantly trying out new ideas. Most of the applications will go unnoticed but some will gain popularity. Popular ideas will get copied and combined with other popular ideas. This merging of ideas drives the whole software ecosystem into new directions.
Self-organization in software is our best lead so far towards general artificial intelligence and computational creativity. Traditional software engineering and machine learning are too narrowly focused on solving one task at a time. An artificial intelligence must not only be good at playing Go or at recognizing objects but it has to be good at adapting to new situations (that's what intelligence means). This kind of genuine adaptivity can't come from processes that optimize only for specific goals. Self-organization is currently an academic research topic and no practical applications exist yet.
The table below summarizes the different levels of flexibility in software.
While most current software fits in the stereotypical view of programs as collections of rules that define what to do in each situation, software is by no means limited to such rigidity. Flexible computational models bring us programs that play complex games, recognize objects and, in the future, perhaps even lead to an artificial intelligence.