Futures and promises
Encyclopedia
In computer science
, future, promise, and delay refer to constructs used for synchronization in some concurrent programming languages. They describe an object that acts as a proxy for a result that is initially not known, usually because the computation
of its value has not yet completed.
The term "promise" was proposed in 1976 by Daniel P. Friedman
and David Wise,
and Peter Hibbard called it "eventual".
A somewhat similar concept "future" was introduced in 1977 in a paper by Henry Baker
and Carl Hewitt
.
The terms "future", "promise", and "delay" are often used interchangeably, although some differences in usage between "future" and "promise" are discussed below. Setting the value of a future is also called "resolving", "fulfilling", or "binding" it.
). Obtaining the value of an explicit future can be called "stinging" or "forcing". Explicit futures may be implemented as a library, whereas implicit futures require language support.
The original Baker and Hewitt paper described implicit futures, which are naturally supported in the Actor model
of computation and pure object-oriented programming languages like Smalltalk
. The Friedman and Wise paper described only explicit futures, probably reflecting the difficulty of efficiently implementing implicit futures on stock hardware. The difficulty is that stock hardware does not deal with futures for primitive data types like integers. For example, an add instruction does not know how to deal with 3 + future factorial(100000). In pure object or Actor languages this problem can be solved by sending future factorial(100000) the message +[3], which asks the future to add 3 to itself and return the result. Note that the message passing approach works regardless of when factorial(100000) finishes computation and that no stinging/forcing is required.
in distributed systems
. For instance, futures enable promise pipelining, as implemented in the E
and Joule
programming languages, which was also called call-stream in the Argus
programming language.
Consider an expression involving conventional remote procedure call
s, such as:
which could be expanded to
Each statement requires a message to be sent and a reply received before the next statement can proceed. Suppose, for example, that x, y, t1, and t2 are all located on the same remote machine. In this case, two complete network round-trips to that machine must take place before the third statement can begin to execute. The third statement will then cause yet another round-trip to the same remote machine.
Using futures, the above expression could be written
which could be expanded to
The syntax used here is that of the E programming language, where x <- a means to send the message a asynchronously to x. All three variables are immediately assigned futures for their results, and execution proceeds to subsequent statements. Later attempts to resolve the value of t3 may cause a delay; however, pipelining can reduce the number of round-trips required. If, as in the previous example, x, y, t1, and t2 are all located on the same remote machine, a pipelined implementation can compute t3 with one round-trip instead of three. Because all three messages are destined for objects which are on the same remote machine, only one request need be sent and only one response need be received containing the result. Note also that the send t1 <- c(t2) would not block even if t1 and t2 were on different machines to each other, or to x or y.
Promise pipelining should be distinguished from parallel asynchronous message passing. In a system supporting parallel message passing but not pipelining, the message sends x <- a and y <- b in the above example could proceed in parallel, but the send of t1 <- c(t2) would have to wait until both t1 and t2 had been received, even when x, y, t1, and t2 are on the same remote machine. The relative latency advantage of pipelining becomes even greater in more complicated situations involving many messages.
Promise pipelining also should not be confused with pipelined message processing in Actor systems, where it is possible for an actor to specify and begin executing a behaviour for the next message before having completed processing of the current message.
, E
, and AmbientTalk
, it is possible to obtain a "read-only view" of a future, which allows reading its value when resolved, but does not permit resolving it:
Support for read-only views is consistent with the Principle of Least Authority, since it enables the ability to set the value to be restricted to subjects that need to set it. In a system that also supports pipelining, the sender of an asynchronous message (with result) receives the read-only promise for the result, and the target of the message receives the resolver.
, define futures that are associated with a specific thread that computes the future's value. This computation may be started either eagerly
when the future is created, or lazily
when its value is first needed. A lazy future is similar to a thunk
(in the sense of a delayed computation).
Alice ML also supports futures that can be resolved by any thread, and calls these "promises". Note that this usage of "promise" is different from its usage in E as described above: an Alice promise is not a read-only view, and Alice also does not support pipelining for promises themselves. Instead, pipelining naturally happens for futures (including ones associated with promises).
However, in some systems it may also be possible to attempt to "immediately" or "synchronously" access a future's value. Then there is a design choice to be made:
) is a future with blocking semantics as defined above. An I-structure is a data structure
containing I-vars. A related synchronization construct that can be set multiple times with different values is called an M-var. M-vars support atomic operations to "take" or "put" the current value, where taking the value also sets the M-var back to its initial "empty" state.
A concurrent logic variable is similar to a future, but is updated by unification, in the same way as logic variables in logic programming
. Thus it can be bound more than once to unifiable values (but cannot be set back to an empty or unresolved state). The dataflow variables of Oz act as concurrent logic variables, and also have blocking semantics as mentioned above.
A concurrent constraint variable is a generalization of concurrent logic variables to support constraint logic programming: the constraint may be narrowed multiple times, indicating smaller sets of possible values. Typically there is a way to specify a thunk that should be run whenever the constraint is narrowed further; this is necessary to support constraint propagation.
To implement implicit lazy thread-specific futures (as provided by Alice ML, for example) in terms in non-thread-specific futures, requires a mechanism to determine when the future's value is first needed (for example, the WaitNeeded construct in Oz). If all values are objects, then the ability to implement transparent forwarding objects is sufficient, since the first message sent to the forwarder indicates that the future's value is needed.
Non-thread-specific futures can be implemented in terms of thread-specific futures, assuming that the system supports message passing, by having the resolving thread send a message to the future's own thread. However, this could be argued to be unnecessary complexity: in programming languages based on threads, the most expressive approach appears to be to provide a combination of non-thread-specific futures, read-only views, and either a 'WaitNeeded' construct or support for transparent forwarding.
. However, the term lazy evaluation is most often used to refer to an evaluation strategy
for all computation in a language, whereas lazy futures represent specific values that are computed lazily, even in a language where computation is normally strict or eager
. In C++0x
such lazy futures can be created by passing the
is defined by how it responds to an Eval message with environment E and customer C as follows: The future expression responds to the Eval message by sending the customer C a newly created actor F (the proxy for the response of evaluating ) as a return value concurrently with sending an Eval message with environment E and customer F. The default behavior of F is as follows:
However, some futures can deal with requests in special ways to provide greater parallelism. For example, the expression 1 + future factorial(n) can create a new future that will behave like the number 1+factorial(n). This trick does not always work. For example the following conditional expression:
suspends until the future for factorial(n) has responded to the request asking if m is greater than itself.
and Act 1
. The use of logic variables for communication in concurrent
logic programming
languages was quite similar to futures. These started with "Prolog with Freeze" and "IC Prolog", and became a true concurrency primitive with Relational Language, Concurrent Prolog, Guarded Horn Clauses (GHC), Parlog
, Vulcan, Janus
, Mozart
/Oz
, Flow Java
, and Alice ML
. The single-assignment "I-var" from dataflow programming languages, originating in Id
and included in Reppy's "Concurrent ML
", is much like the concurrent logic variable.
The promise pipelining technique (using futures to overcome latency) was invented by Barbara Liskov
and Liuba Shrira in 1988, and independently by Mark S. Miller
, Dean Tribble and Rob Jellinghaus in the context of Project Xanadu
circa 1989.
The term "promise" was coined by Liskov and Shrira, although they referred to the pipelining mechanism by the name "call-stream", which is now rarely used.
Both the design described in Liskov and Shrira's paper, and the implementation of promise pipelining in Xanadu, had the limitation that promise values were not first-class: an argument to, or the value returned by a call or send could not directly be a promise (so the example of promise pipelining given earlier, which uses a promise for the result of one send as an argument to another, would not have been directly expressible in the call-stream design or in the Xanadu implementation). It appears that promises and call-streams were never implemented in any public release of Argus (the programming language used in the Liskov and Shrira paper); Argus development stopped around 1988. The Xanadu implementation of promise pipelining only became publicly available with the release of the source code for Udanax Gold in 1999, and was never explained in any published document. The later implementations in Joule and E support fully first-class promises and resolvers.
Several early Actor languages, including the Act series of languages, supported both parallel message passing and pipelined message processing, but not promise pipelining. (Although it is technically possible to implement the last of these features in terms of the first two, there is no evidence that the Act languages did so.)
Languages also supporting promise pipelining include:
Library-based implementations of futures:
Computer science
Computer science or computing science is the study of the theoretical foundations of information and computation and of practical techniques for their implementation and application in computer systems...
, future, promise, and delay refer to constructs used for synchronization in some concurrent programming languages. They describe an object that acts as a proxy for a result that is initially not known, usually because the computation
Computation
Computation is defined as any type of calculation. Also defined as use of computer technology in Information processing.Computation is a process following a well-defined model understood and expressed in an algorithm, protocol, network topology, etc...
of its value has not yet completed.
The term "promise" was proposed in 1976 by Daniel P. Friedman
Daniel P. Friedman
Daniel Paul Friedman is a professor of Computer Science at Indiana University in Bloomington, Indiana. His research focuses on programming languages, and he is a prominent author in the field....
and David Wise,
and Peter Hibbard called it "eventual".
A somewhat similar concept "future" was introduced in 1977 in a paper by Henry Baker
Henry Baker (computer scientist)
Henry Givens Baker Jr. is a computer scientist who has made contributions in garbage collection, functional programming languages, and linear logic. He was also one of the founders of Symbolics...
and Carl Hewitt
Carl Hewitt
Carl Hewitt is Board Chair of the International Society for Inconsistency Robustness. He has been a Visiting Professor at Stanford University and the University of Keio. In 2000, he became emeritus in the EECS department at MIT....
.
The terms "future", "promise", and "delay" are often used interchangeably, although some differences in usage between "future" and "promise" are discussed below. Setting the value of a future is also called "resolving", "fulfilling", or "binding" it.
Implicit vs explicit
Use of futures may be implicit (any use of the future automatically obtains its value, as if it were an ordinary reference) or explicit (the user must call a function to obtain the value, such as the get method of java.util.concurrent.Future in JavaJava (programming language)
Java is a programming language originally developed by James Gosling at Sun Microsystems and released in 1995 as a core component of Sun Microsystems' Java platform. The language derives much of its syntax from C and C++ but has a simpler object model and fewer low-level facilities...
). Obtaining the value of an explicit future can be called "stinging" or "forcing". Explicit futures may be implemented as a library, whereas implicit futures require language support.
The original Baker and Hewitt paper described implicit futures, which are naturally supported in the Actor model
Actor model
In computer science, the Actor model is a mathematical model of concurrent computation that treats "actors" as the universal primitives of concurrent digital computation: in response to a message that it receives, an actor can make local decisions, create more actors, send more messages, and...
of computation and pure object-oriented programming languages like Smalltalk
Smalltalk
Smalltalk is an object-oriented, dynamically typed, reflective programming language. Smalltalk was created as the language to underpin the "new world" of computing exemplified by "human–computer symbiosis." It was designed and created in part for educational use, more so for constructionist...
. The Friedman and Wise paper described only explicit futures, probably reflecting the difficulty of efficiently implementing implicit futures on stock hardware. The difficulty is that stock hardware does not deal with futures for primitive data types like integers. For example, an add instruction does not know how to deal with 3 + future factorial(100000). In pure object or Actor languages this problem can be solved by sending future factorial(100000) the message +[3], which asks the future to add 3 to itself and return the result. Note that the message passing approach works regardless of when factorial(100000) finishes computation and that no stinging/forcing is required.
Promise pipelining
The use of futures can dramatically reduce latencyLatency (engineering)
Latency is a measure of time delay experienced in a system, the precise definition of which depends on the system and the time being measured. Latencies may have different meaning in different contexts.-Packet-switched networks:...
in distributed systems
Distributed computing
Distributed computing is a field of computer science that studies distributed systems. A distributed system consists of multiple autonomous computers that communicate through a computer network. The computers interact with each other in order to achieve a common goal...
. For instance, futures enable promise pipelining, as implemented in the E
E (programming language)
E is an object-oriented programming language for secure distributed computing, created by Mark S. Miller, Dan Bornstein, and others at Electric Communities in 1997. E is mainly descended from the concurrent language Joule and from Original-E, a set of extensions to Java for secure distributed...
and Joule
Joule (programming language)
Joule is a concurrent dataflow programming language, designed for building distributed applications. It is so concurrent, that the order of statements within a block is irrelevant to the operation of the block. Statements are executed whenever possible, based on their inputs. Everything in Joule...
programming languages, which was also called call-stream in the Argus
Argus (programming language)
Argus is a programming language created at MIT by Barbara Liskov between 1982 and 1988, in collaboration with Maurice Herlihy, Paul Johnson, Robert Scheifler, and William Weihl. It is an extension of the CLU language, and utilizes most of the same syntax and semantics...
programming language.
Consider an expression involving conventional remote procedure call
Remote procedure call
In computer science, a remote procedure call is an inter-process communication that allows a computer program to cause a subroutine or procedure to execute in another address space without the programmer explicitly coding the details for this remote interaction...
s, such as:
which could be expanded to
Each statement requires a message to be sent and a reply received before the next statement can proceed. Suppose, for example, that x, y, t1, and t2 are all located on the same remote machine. In this case, two complete network round-trips to that machine must take place before the third statement can begin to execute. The third statement will then cause yet another round-trip to the same remote machine.
Using futures, the above expression could be written
which could be expanded to
The syntax used here is that of the E programming language, where x <- a means to send the message a asynchronously to x. All three variables are immediately assigned futures for their results, and execution proceeds to subsequent statements. Later attempts to resolve the value of t3 may cause a delay; however, pipelining can reduce the number of round-trips required. If, as in the previous example, x, y, t1, and t2 are all located on the same remote machine, a pipelined implementation can compute t3 with one round-trip instead of three. Because all three messages are destined for objects which are on the same remote machine, only one request need be sent and only one response need be received containing the result. Note also that the send t1 <- c(t2) would not block even if t1 and t2 were on different machines to each other, or to x or y.
Promise pipelining should be distinguished from parallel asynchronous message passing. In a system supporting parallel message passing but not pipelining, the message sends x <- a and y <- b in the above example could proceed in parallel, but the send of t1 <- c(t2) would have to wait until both t1 and t2 had been received, even when x, y, t1, and t2 are on the same remote machine. The relative latency advantage of pipelining becomes even greater in more complicated situations involving many messages.
Promise pipelining also should not be confused with pipelined message processing in Actor systems, where it is possible for an actor to specify and begin executing a behaviour for the next message before having completed processing of the current message.
Read-only views
In some programming languages such as OzOz (programming language)
Oz is a multiparadigm programming language, developed in the Programming Systems Lab at Université catholique de Louvain, for programming language education. It has a canonical textbook: Concepts, Techniques, and Models of Computer Programming....
, E
E (programming language)
E is an object-oriented programming language for secure distributed computing, created by Mark S. Miller, Dan Bornstein, and others at Electric Communities in 1997. E is mainly descended from the concurrent language Joule and from Original-E, a set of extensions to Java for secure distributed...
, and AmbientTalk
AmbientTalk
AmbientTalk is an experimental object-oriented distributed programming language developed at the Programming Technology Laboratory at the Vrije Universiteit Brussel, Belgium...
, it is possible to obtain a "read-only view" of a future, which allows reading its value when resolved, but does not permit resolving it:
- In Oz, the !! operator is used to obtain a read-only view.
- In E and AmbientTalk, a future is represented by a pair of values called a "promise/resolver pair". The promise represents the read-only view, and the resolver is required in order to set the future's value.
- In C++0xC++0xC++11, also formerly known as C++0x, is the name of the most recent iteration of the C++ programming language, replacing C++03, approved by the ISO as of 12 August 2011...
astd::future
provides a read-only view. The value is set directly by using astd::promise
, or set to the result of a function call usingstd::packaged_task
orstd::async
. - In the Dojo ToolkitDojo ToolkitDojo Toolkit is an open source modular JavaScript library designed to ease the rapid development of cross-platform, JavaScript/Ajax-based applications and web sites. It was started by Alex Russell, Dylan Schiemann, David Schontzler, and others in 2004 and is dual-licensed under the modified BSD...
's Deferred API as of version 1.5, a "consumer-only promise object" represents a read-only view. - In Alice ML, futures only provide a "read-only view", whereas a promise contains both a future and the ability to resolve the future
Support for read-only views is consistent with the Principle of Least Authority, since it enables the ability to set the value to be restricted to subjects that need to set it. In a system that also supports pipelining, the sender of an asynchronous message (with result) receives the read-only promise for the result, and the target of the message receives the resolver.
Thread-specific futures
Some languages, such as Alice MLAlice (programming language)
Alice ML is a functional programming language designed by the at Saarland University. It is a dialect of Standard ML, augmented with support for lazy evaluation, concurrency and constraint programming.-Overview:Alice extends Standard ML in a number of ways that distinguish it from its predecessor...
, define futures that are associated with a specific thread that computes the future's value. This computation may be started either eagerly
Eager evaluation
In computer programming, eager evaluation or greedy evaluation is the evaluation strategy in most traditional programming languages. In eager evaluation an expression is evaluated as soon as it gets bound to a variable. The term is typically used to contrast lazy evaluation, where expressions are...
when the future is created, or lazily
Lazy evaluation
In programming language theory, lazy evaluation or call-by-need is an evaluation strategy which delays the evaluation of an expression until the value of this is actually required and which also avoids repeated evaluations...
when its value is first needed. A lazy future is similar to a thunk
Thunk
Thunk may refer to:* Thunk , a piece of code to perform a delayed computation * Thunk : a feature of some virtual function table implementations...
(in the sense of a delayed computation).
Alice ML also supports futures that can be resolved by any thread, and calls these "promises". Note that this usage of "promise" is different from its usage in E as described above: an Alice promise is not a read-only view, and Alice also does not support pipelining for promises themselves. Instead, pipelining naturally happens for futures (including ones associated with promises).
Blocking vs non-blocking semantics
If the value of a future is accessed asynchronously, for example by sending a message to it, or by explicitly waiting for it using a construct such as when in E, then there is no difficulty in delaying until the future is resolved before the message can be received or the wait completes. This is the only case to be considered in purely asynchronous systems such as pure Actor languages.However, in some systems it may also be possible to attempt to "immediately" or "synchronously" access a future's value. Then there is a design choice to be made:
- the access could block the current thread or process until the future is resolved. This is the semantics of dataflow variables in the Oz programming languageOz (programming language)Oz is a multiparadigm programming language, developed in the Programming Systems Lab at Université catholique de Louvain, for programming language education. It has a canonical textbook: Concepts, Techniques, and Models of Computer Programming....
. - the attempted synchronous access could always signal an error, for example throwing an exception. This is the semantics of remote promises in E.
- potentially, the access could succeed if the future is already resolved, but signal an error if it is not. This would have the disadvantage of introducing nondeterminism and the potential for race conditions, and does not appear to be a common design choice.
- in C++0xC++0xC++11, also formerly known as C++0x, is the name of the most recent iteration of the C++ programming language, replacing C++03, approved by the ISO as of 12 August 2011...
, a thread that needs the value of a future can block until it is available by calling thewait
orget
member functions. You can also specify a timeout on the wait using thewait_for
orwait_until
member functions to avoid indefinite blocking. If the future arose from a call tostd::async
then a blocking wait (without a timeout) may cause synchronous invocation of the function to compute the result on the waiting thread.
Related constructs
An I-var (as in the Id programming languageId (programming language)
Id is a general-purpose parallel programming language, developed by Arvind and Nikhil, at MIT, in the late 1970 and throughout the 1980s. The major subset of Id is a purely functional programming language with non-strict semantics...
) is a future with blocking semantics as defined above. An I-structure is a data structure
Data structure
In computer science, a data structure is a particular way of storing and organizing data in a computer so that it can be used efficiently.Different kinds of data structures are suited to different kinds of applications, and some are highly specialized to specific tasks...
containing I-vars. A related synchronization construct that can be set multiple times with different values is called an M-var. M-vars support atomic operations to "take" or "put" the current value, where taking the value also sets the M-var back to its initial "empty" state.
A concurrent logic variable is similar to a future, but is updated by unification, in the same way as logic variables in logic programming
Logic programming
Logic programming is, in its broadest sense, the use of mathematical logic for computer programming. In this view of logic programming, which can be traced at least as far back as John McCarthy's [1958] advice-taker proposal, logic is used as a purely declarative representation language, and a...
. Thus it can be bound more than once to unifiable values (but cannot be set back to an empty or unresolved state). The dataflow variables of Oz act as concurrent logic variables, and also have blocking semantics as mentioned above.
A concurrent constraint variable is a generalization of concurrent logic variables to support constraint logic programming: the constraint may be narrowed multiple times, indicating smaller sets of possible values. Typically there is a way to specify a thunk that should be run whenever the constraint is narrowed further; this is necessary to support constraint propagation.
Relations between the expressiveness of different forms of future
Eager thread-specific futures can be straightforwardly implemented in terms of non-thread-specific futures, by creating a thread to calculate the value at the same time as creating the future. In this case it is desirable to return a read-only view to the client, so that only the newly created thread is able to resolve this future.To implement implicit lazy thread-specific futures (as provided by Alice ML, for example) in terms in non-thread-specific futures, requires a mechanism to determine when the future's value is first needed (for example, the WaitNeeded construct in Oz). If all values are objects, then the ability to implement transparent forwarding objects is sufficient, since the first message sent to the forwarder indicates that the future's value is needed.
Non-thread-specific futures can be implemented in terms of thread-specific futures, assuming that the system supports message passing, by having the resolving thread send a message to the future's own thread. However, this could be argued to be unnecessary complexity: in programming languages based on threads, the most expressive approach appears to be to provide a combination of non-thread-specific futures, read-only views, and either a 'WaitNeeded' construct or support for transparent forwarding.
Relation to lazy evaluation
Lazy futures, where the computation of the future's value starts when the value is first needed, are closely related to lazy evaluationLazy evaluation
In programming language theory, lazy evaluation or call-by-need is an evaluation strategy which delays the evaluation of an expression until the value of this is actually required and which also avoids repeated evaluations...
. However, the term lazy evaluation is most often used to refer to an evaluation strategy
Evaluation strategy
In computer science, an evaluation strategy is a set of rules for evaluating expressions in a programming language. Emphasis is typically placed on functions or operators: an evaluation strategy defines when and in what order the arguments to a function are evaluated, when they are substituted...
for all computation in a language, whereas lazy futures represent specific values that are computed lazily, even in a language where computation is normally strict or eager
Eager evaluation
In computer programming, eager evaluation or greedy evaluation is the evaluation strategy in most traditional programming languages. In eager evaluation an expression is evaluated as soon as it gets bound to a variable. The term is typically used to contrast lazy evaluation, where expressions are...
. In C++0x
C++0x
C++11, also formerly known as C++0x, is the name of the most recent iteration of the C++ programming language, replacing C++03, approved by the ISO as of 12 August 2011...
such lazy futures can be created by passing the
std::launch::sync
launch policy to std::async
, along with the function to compute the value.Semantics of futures in the Actor model
In the Actor model, an expression of the form future- When F receives a request R, then it checks to see if it has already received a response (that can either be a return value or a thrown exception) from evaluating
proceeding as follows:
- 1) If it already has a response V, then
-
- If V is a return value, then it is sent the request R.
- If V is an exception, then it is thrown to the customer of the request R.
-
- 2) If it does not already have a response, then R is stored in the queue of requests inside the F.
- When F receives the response V from evaluating
, then V is stored in F and
-
-
- If V is a return value, then all of the queued requests are sent to V.
- If V is an exception, then it is thrown to the customer of the each queued request.
-
However, some futures can deal with requests in special ways to provide greater parallelism. For example, the expression 1 + future factorial(n) can create a new future that will behave like the number 1+factorial(n). This trick does not always work. For example the following conditional expression:
- if m>future factorial(n) then print("bigger") else print("smaller")
suspends until the future for factorial(n) has responded to the request asking if m is greater than itself.
History
The future and/or promise constructs were first implemented in programming languages such as MultiLispMultiLisp
MultiLisp is a functional programming language and dialect of the Lisp dialect Scheme, extended with constructs for parallel execution and shared memory; MultiLisp is implemented in Interlisp. These extensions involve side effects, rendering MultiLisp non-deterministic...
and Act 1
Actor model
In computer science, the Actor model is a mathematical model of concurrent computation that treats "actors" as the universal primitives of concurrent digital computation: in response to a message that it receives, an actor can make local decisions, create more actors, send more messages, and...
. The use of logic variables for communication in concurrent
Concurrency (computer science)
In computer science, concurrency is a property of systems in which several computations are executing simultaneously, and potentially interacting with each other...
logic programming
Logic programming
Logic programming is, in its broadest sense, the use of mathematical logic for computer programming. In this view of logic programming, which can be traced at least as far back as John McCarthy's [1958] advice-taker proposal, logic is used as a purely declarative representation language, and a...
languages was quite similar to futures. These started with "Prolog with Freeze" and "IC Prolog", and became a true concurrency primitive with Relational Language, Concurrent Prolog, Guarded Horn Clauses (GHC), Parlog
Parlog
Parlog is a logic programming language designed for efficient utilization of parallel computer architectures. Its semantics is based on first order predicate logic. It expresses concurrency, interprocess communication, indeterminacy and synchronization within the declarative language framework. It...
, Vulcan, Janus
Janus (programming language)
The name Janus refers to at least two computer programming languages or partial descriptions of possible computer programing languages:-Concurrent Constraint Programming:...
, Mozart
Mozart Programming System
The Mozart Programming System is a multiplatform implementation of the Oz programming language developed by an international group, the Mozart Consortium, which originally consisted of Saarland University, the Swedish Institute of Computer Science, and the Université catholique de Louvain.Mozart...
/Oz
Oz (programming language)
Oz is a multiparadigm programming language, developed in the Programming Systems Lab at Université catholique de Louvain, for programming language education. It has a canonical textbook: Concepts, Techniques, and Models of Computer Programming....
, Flow Java
Flow Java
Flow Java is a conservative extension to the Java programming language.It integrates single assignment variables and logic variables, to Java.Its development was influenced by Mozart/Oz....
, and Alice ML
Alice (programming language)
Alice ML is a functional programming language designed by the at Saarland University. It is a dialect of Standard ML, augmented with support for lazy evaluation, concurrency and constraint programming.-Overview:Alice extends Standard ML in a number of ways that distinguish it from its predecessor...
. The single-assignment "I-var" from dataflow programming languages, originating in Id
Id (programming language)
Id is a general-purpose parallel programming language, developed by Arvind and Nikhil, at MIT, in the late 1970 and throughout the 1980s. The major subset of Id is a purely functional programming language with non-strict semantics...
and included in Reppy's "Concurrent ML
Concurrent ML
Concurrent ML is a concurrent extension of the Standard ML programming language.-Sample Code:Here is sample code to print "hello, world" to the console. It spawns a thread which creates a channel for strings. This thread then spawns another thread which prints the first string that is received...
", is much like the concurrent logic variable.
The promise pipelining technique (using futures to overcome latency) was invented by Barbara Liskov
Barbara Liskov
Barbara Liskov is a computer scientist. She is currently the Ford Professor of Engineering in the MIT School of Engineering's Electrical Engineering and Computer Science department and an Institute Professor at the Massachusetts Institute of Technology.-Life and career:She earned her BA in...
and Liuba Shrira in 1988, and independently by Mark S. Miller
Mark S. Miller
Mark S. Miller is an American computer scientist. He is known for his work as one of the participants in the 1979 hypertext project known as Project Xanadu; for inventing Miller Columns; as the co-creator of the Agoric Paradigm of market-based distributed secure computing; and the open-source...
, Dean Tribble and Rob Jellinghaus in the context of Project Xanadu
Project Xanadu
Project Xanadu was the first hypertext project, founded in 1960 by Ted Nelson. Administrators of Project Xanadu have declared it an improvement over the World Wide Web, with mission statement: "Today's popular software simulates paper...
circa 1989.
The term "promise" was coined by Liskov and Shrira, although they referred to the pipelining mechanism by the name "call-stream", which is now rarely used.
Both the design described in Liskov and Shrira's paper, and the implementation of promise pipelining in Xanadu, had the limitation that promise values were not first-class: an argument to, or the value returned by a call or send could not directly be a promise (so the example of promise pipelining given earlier, which uses a promise for the result of one send as an argument to another, would not have been directly expressible in the call-stream design or in the Xanadu implementation). It appears that promises and call-streams were never implemented in any public release of Argus (the programming language used in the Liskov and Shrira paper); Argus development stopped around 1988. The Xanadu implementation of promise pipelining only became publicly available with the release of the source code for Udanax Gold in 1999, and was never explained in any published document. The later implementations in Joule and E support fully first-class promises and resolvers.
Several early Actor languages, including the Act series of languages, supported both parallel message passing and pipelined message processing, but not promise pipelining. (Although it is technically possible to implement the last of these features in terms of the first two, there is no evidence that the Act languages did so.)
List of implementations
Languages supporting futures, promises, concurrent logic variables, dataflow variables, or I-vars include:- Act 1, 2 and 3
- IdId (programming language)Id is a general-purpose parallel programming language, developed by Arvind and Nikhil, at MIT, in the late 1970 and throughout the 1980s. The major subset of Id is a purely functional programming language with non-strict semantics...
(I-vars and M-vars only) - Glasgow HaskellHaskell (programming language)Haskell is a standardized, general-purpose purely functional programming language, with non-strict semantics and strong static typing. It is named after logician Haskell Curry. In Haskell, "a function is a first-class citizen" of the programming language. As a functional programming language, the...
(I-vars and M-vars only) - Alice MLAlice (programming language)Alice ML is a functional programming language designed by the at Saarland University. It is a dialect of Standard ML, augmented with support for lazy evaluation, concurrency and constraint programming.-Overview:Alice extends Standard ML in a number of ways that distinguish it from its predecessor...
- ClojureClojureClojure |closure]]") is a recent dialect of the Lisp programming language created by Rich Hickey. It is a general-purpose language supporting interactive development that encourages a functional programming style, and simplifies multithreaded programming....
- IoIo (programming language)Io is a pure object-oriented programming language inspired by Smalltalk, Self, Lua, Lisp, Act1, and NewtonScript. Io has a prototype-based object model similar to the ones in Self and NewtonScript, eliminating the distinction between instance and class. Like Smalltalk, everything is an object and...
- OzOz (programming language)Oz is a multiparadigm programming language, developed in the Programming Systems Lab at Université catholique de Louvain, for programming language education. It has a canonical textbook: Concepts, Techniques, and Models of Computer Programming....
version 3 - Oxygene
- MultiLispMultiLispMultiLisp is a functional programming language and dialect of the Lisp dialect Scheme, extended with constructs for parallel execution and shared memory; MultiLisp is implemented in Interlisp. These extensions involve side effects, rendering MultiLisp non-deterministic...
- ABCL/f
- Lucid (dataflow only)
- Scheme
- Racket
- AmbientTalkAmbientTalkAmbientTalk is an experimental object-oriented distributed programming language developed at the Programming Technology Laboratory at the Vrije Universiteit Brussel, Belgium...
(including first-class resolvers and read-only promises) - RR (programming language)R is a programming language and software environment for statistical computing and graphics. The R language is widely used among statisticians for developing statistical software, and R is widely used for statistical software development and data analysis....
(promises for lazy evaluation - still single threaded) - Flow JavaFlow JavaFlow Java is a conservative extension to the Java programming language.It integrates single assignment variables and logic variables, to Java.Its development was influenced by Mozart/Oz....
- μC++
- PythonPython (programming language)Python is a general-purpose, high-level programming language whose design philosophy emphasizes code readability. Python claims to "[combine] remarkable power with very clear syntax", and its standard library is large and comprehensive...
3.2, as proposed by the PEP 3148 - Proposed for C# 5 (through the await keyword)
Languages also supporting promise pipelining include:
- JouleJoule (programming language)Joule is a concurrent dataflow programming language, designed for building distributed applications. It is so concurrent, that the order of statements within a block is irrelevant to the operation of the block. Statements are executed whenever possible, based on their inputs. Everything in Joule...
- EE (programming language)E is an object-oriented programming language for secure distributed computing, created by Mark S. Miller, Dan Bornstein, and others at Electric Communities in 1997. E is mainly descended from the concurrent language Joule and from Original-E, a set of extensions to Java for secure distributed...
Library-based implementations of futures:
-
scala.parallel.Future
andscala.actors.Future
in Scala -
java.util.concurrent.Future
in JavaJava (programming language)Java is a programming language originally developed by James Gosling at Sun Microsystems and released in 1995 as a core component of Sun Microsystems' Java platform. The language derives much of its syntax from C and C++ but has a simpler object model and fewer low-level facilities... - C++11 (new revision of the C++ standard), the Boost library and the Dlib C++ Library
- The ref_send library of the Waterken server supports explicit futures in JavaScriptJavaScriptJavaScript is a prototype-based scripting language that is dynamic, weakly typed and has first-class functions. It is a multi-paradigm language, supporting object-oriented, imperative, and functional programming styles....
. - Q is a stand-alone implementation of explicit promises and deferreds for many JavaScriptJavaScriptJavaScript is a prototype-based scripting language that is dynamic, weakly typed and has first-class functions. It is a multi-paradigm language, supporting object-oriented, imperative, and functional programming styles....
engines, based on ref_send. - The Dojo ToolkitDojo ToolkitDojo Toolkit is an open source modular JavaScript library designed to ease the rapid development of cross-platform, JavaScript/Ajax-based applications and web sites. It was started by Alex Russell, Dylan Schiemann, David Schontzler, and others in 2004 and is dual-licensed under the modified BSD...
supplies both promises and Twisted style Deferreds for JavaScript. - Promised-IO provides promises in JavaScriptJavaScriptJavaScript is a prototype-based scripting language that is dynamic, weakly typed and has first-class functions. It is a multi-paradigm language, supporting object-oriented, imperative, and functional programming styles....
. - The Parallel Extensions library for C#
- SRFI-45 is a specification for library-based lazy and eager explicit futures in Scheme.
- OCamlObjective CamlOCaml , originally known as Objective Caml, is the main implementation of the Caml programming language, created by Xavier Leroy, Jérôme Vouillon, Damien Doligez, Didier Rémy and others in 1996...
's Lazy module implements lazy explicit futures. - pythonfutures and TwistedTwisted (software)Twisted is an event-driven network programming framework written in Python and licensed under the MIT License.Twisted projects variously support TCP, UDP, SSL/TLS, IP Multicast, Unix domain sockets, a large number of protocols , and much more...
's Deferreds in PythonPython (programming language)Python is a general-purpose, high-level programming language whose design philosophy emphasizes code readability. Python claims to "[combine] remarkable power with very clear syntax", and its standard library is large and comprehensive... - The Promise gem in RubyRuby (programming language)Ruby is a dynamic, reflective, general-purpose object-oriented programming language that combines syntax inspired by Perl with Smalltalk-like features. Ruby originated in Japan during the mid-1990s and was first developed and designed by Yukihiro "Matz" Matsumoto...
- Sub::Future and Reflex for Perl
- Eager Future2 and PCall for Common LispCommon LispCommon Lisp, commonly abbreviated CL, is a dialect of the Lisp programming language, published in ANSI standard document ANSI INCITS 226-1994 , . From the ANSI Common Lisp standard the Common Lisp HyperSpec has been derived for use with web browsers...
External links
- Future Value and Promise Pipelining at the Portland Pattern RepositoryPortland Pattern RepositoryThe Portland Pattern Repository is a repository for computer programming design patterns. It was accompanied by a companion website, WikiWikiWeb, which was the world's first wiki....
- Easy Threading with Futures in Python