Programming where problems are described, or conditions
on a solution are described, and the computer finds a solution. Often it involves the separation of "facts" from operations on the facts.
"Declarative Programming" has also been described as a model of computation that "generalizes the pure functional model". That is, all pure functional programs are declarative programs, and DeclarativeProgramming
retains almost all of the advantages of FunctionalProgramming
. This is explained in more detail in the book ConceptsTechniquesAndModelsOfComputerProgramming
Subcategories of DeclarativeProgramming
, and ConstraintLogicProgramming
(which, as its name suggests, is a hybrid of the two - see ConstraintAndLogicProgramming
While the above is nice in a HandWaving
way, it is vague and leads to of HolyWar
s about whether this or that language is 'declarative' or effectively supports 'DeclarativeProgramming
'. Due to the vagueness of the original definition, DeclarativeProgramming
is effectively a sliding scale. The following operational characteristics might be used to judge the extent to which a programming model is declarative:
- In DeclarativeProgramming, order of statements and expressions should not affect program semantics. For example, they should not affect the termination characteristics and should not affect the observable IO properties, and ideally shouldn't affect performance.
- In DeclarativeProgramming, replication of a statement should not affect program semantics. What matters is that some fact or constraint exists, not how many times it is declared or computed. This allows refactoring and abstraction of statements, and is also a basis for many optimizations.
Or, essentially, DeclarativeProgramming
should exhibit properties of commutativity
across statements. DeclarativeProgramming
models vary widely in how they support SideEffect
s, synchronization and coordination, modularity, composition, security, consistency, and IO. (To name a few approaches: oracles, single-assignment future values, temporal or reactive semantics, constraint maintenance, graph or TermRewriting
, generative grammars.)
exhibits commutativity and idempotence in-the-small. However, it has traditionally used imperative 'glue' (such as monads) that tend to make composition of statements imperative
at higher levels. The ideal of DeclarativeProgramming
is to keep things 'declarative' even at the top-level (in-the-large, integrating with IO, and across modules). Some disciplined forms of FunctionalProgramming
(such as FunctionalReactiveProgramming
) support far more declarative composition than monads.
There seem to be two distinct types of DeclarativeProgramming
In the first, you describe something, and the computer implements it.
In the second, you use more commands. "Find me all things which satisfy the following conditions."
They appear to be related; The first is passive, lazy. When the information is needed, it is deduced from the description. The second is active, imperative. You tell the computer to get the information now.
I love using a declarative approach to a problem when it fits - and it can fit surprisingly often. Whenever complex algorithms are applied repeatedly to complex and widely varying data, this is an opportunity to simplify using declarative programming.
The most obvious common example of declarative programming is writing database queries. In this case, the evaluation engine is usually a black box -- either because it's proprietary, or you prefer not to look inside it. Optimizing and executing queries efficiently is complex, so the ability to declare the desired query results in terms of a simple algebra or query language is a huge savings of effort.
In some sense, declarative programming is ubiquitous. Every common high-level programming language lets you express mathematical calculations at a high level, without worrying about the mechanisms of register allocation, table lookups for transcendental functions, etc. So declarative programming "in the small" is a technique that every programmer uses every day, without thinking twice about it.
Where declarative programming sometimes becomes a problem is when the evaluation engine isn't expressive enough, or when it exhibits undesirable characteristics - bugs, performance problems. This is an example of a LeakyAbstraction
, since the engine is abstracting algorithmic complexity, and details of the implementation affect program viability. This is particularly frustrating when the engine is a black box. Sometimes you can work around it by tweaking the representation of the problem that is presented to the engine. This problem might explain why many programmers are uncomfortable with this style of programming. Their reaction might be akin to the NotInventedHere
syndrome that works against the use of third-party libraries in general.
Some code prefers to be declarative rather than imperative. For example, imperative code to create a hierarchy of GUI widgets, associated content models and observers, etc. and link them all together can be quite bulky. E.g. creating a widget and initializing it with a label, observer, and layout information might require 10+ lines of code. The bulk mostly occurs because in imperative code, you have to spell out not only what you want the result to look like, but each step needed to achieve the result. This code is a good candidate for externalizing into some sort of declarative modelling language (e.g. an XML template or something). Now you are still describing what the resulting hierarchy of objects looks like, but you don't have to be explicit about all the creation steps because your runtime (or compiler, or ...) can figure that part out itself. Your 10+ lines of imperative code are reduced to a 1 or 2 line specification.
As another example, I've been thinking about scripting languages used for games programming. Games often use home-grown scripting languages in which (for example) a script is run once each frame and must detect events by polling all the conditions it is interested in. Why not design a declarative scripting language that relies on EventDrivenProgramming
(presumably with a TriggerSystem?
tightly integrated into the language)? Then the script author only has to declare what event conditions he is interested in, leaving it up to the engine (or compiler, or ...) to figure out exactly what trigger machinery is needed to efficiently detect when the declared conditions have occurred.
Something like the event mechanism in the ToolCommandLanguage?
See also: DataCentricThinking