Chris Rathman wrote:
> David Hopwood wrote:
>> In some other languages with dataflow variables, they have to be declared.
>> For example in E (www.erights.org), "def x" declares a dataflow variable,
>> while "var x" declares a mutable variable. The latter is equivalent to a
>> variable associated with a first-class mutable "slot" or cell; E's kernel
>> language is similar to Oz in that respect.
>>
>> This allows use of "var" variables that are not guaranteed initialized
>> to be a compile-time error, while not making it any more difficult to use
>> dataflow variables.
>
> Not being familiar with E, I'm guessing that it has the concept of
> Futures, but not the full ability of dataflow variables.

E is not a logic language, so it does not use pass-by-unification as Oz
does, and variable binding is not the same thing as unification. However,
pattern matching in E works in a similar way to unification (I think it
may be slightly less general in some respects).

In addition, variable slots are first-class in E, so you can program
variables of different kinds within the language. Dataflow variables
(more precisely "promises"; see below) and mutable variables are slot
types provided by the base language.

> Hopefully not to be too pedantic, but futures capture part of, but not
> all of the essence of dataflow variables. Specifically, futures does not
> encompass the unification of Oz's dataflow variables.

I think you're using a slightly nonstandard terminology here. The
difference between futures and dataflow variables is not that the
latter are bound by unification; it is that futures are associated
with a thread. (I am counting active objects as threads here.)

The general concept is a "delayed reference", which may be either
unbound or bound to a value, and can be bound at most once.
Sometimes delayed references can also be "broken", which is an
alternative approach to throwing an execption on binding failure.

The following variants of delayed references have been supported by
various languages (this is not a complete list of variants that could
be supported):

 - "futures" (e.g. in Alice ML or MultiLisp) are delayed references
   associated with a thread. This thread is typically created with the
   future, and is the only thread (by convention or enforcement) that
   binds the future's value. See CTM page 336 for a simulation of
   futures in Oz.

 - "lazy futures" are futures that do not start computation of their
   value until the value is needed. Operations that wait on the future's
   value cause it to become needed.

 - "dataflow variables" are delayed references that are not necessarily
   associated with a specific thread; any code with access to the variable
   can bind its value.

 - "concurrent logic variables" are dataflow variables that are bound
   by unification.

 - "concurrent constraint variables" are a generalisation of concurrent
   logic variables that can refer to a range of values, i.e. a basic
   constraint. The restriction on being bound once is relaxed to a
   restriction that the range of values can only be narrowed.

   (This need not be a primitive concept; for example a constraint
   variable may be implemented as a logic variable referring to an
   object that represents the constraint. The object is mutable, but
   enforces the narrowing restriction.)

 - "promises" are dataflow variables that support promise pipelining
   (http://c2.com/cgi/wiki?PromisePipelining).

Notice that support for promise pipelining, binding by unification, and
laziness do not conflict.

In a committed-choice CCP language, concurrent constraint/logic variables
can be bound to different values in different parts of a search tree.

Mostly orthogonal to the above distinctions, waiting on a delayed reference
can be either explicit (as in E's "when-catch" construct) or implicit (as
in Oz).

> Oz allows you to get
> concurrency of futures and unification which manipulates futures without
> having to write a different set of code depending on whether you want
> sequential, concurrent, or logic based functions. Although the question
> of blocking may be a stumbling block to understanding Oz, unification
> implicit within Oz can also be mind altering.  After all, a list
> statement such as:
> 
> X = Y|Z
> 
> is going to blow the imperative mindset when one realizes that X may or
> may not be assigned a value here.
> - If X, Y and Z are known, no values will be assigned at all, but a
>   unification error may occur if the statement does not hold true for
>   the values of X, Y and Z.
> - If Y and Z are known, and X is not, then X will be assigned the value
>   Y|Z.
> - If X and Z are known, then Y will be assigned a value
> - If X is known but neither Y or Z is known, then a constraint is placed
>   in the store which will be used for verification when code later tries
>   to do an assignment.
> - If X, Y, and Z are unknown, then the constraint is simply stored off
>   for future processing.

This example is equivalent to the pattern match "X ~= [Y]+Z" in E (see
<http://www.erights.org/elang/kernel/MatchBindExpr.html>).

In E it is also possible to write "X := [Y]+Z", which requires X to be
a mutable variable, or "bind X := [Y]+Z", which requires X to be an
unbound promise.

I'd like to clarify something about the last two cases in your example,
though. The effect in these cases is just to bind the variable X to the
cons cell Y|Z, which succeeds immediately. In fact unification in Oz and
pattern matching in E always succeed or fail promptly (in time proportional
to the sizes of the arguments, roughly speaking); they don't create active
propagators (unlike, say, "I >: 42" in Oz).

E supports cons cells (and other structures) that refer to dataflow
variables, but has no language support for propagators. It is not clear
that propagators need to be supported in a base language, though; they
can be provided as a library. Oz has some syntactic sugar for arithmetic
FD constraints, but that could be simulated by macros or operator
overloading.

Personally, I think it is preferable to separate pattern matching or
unification from assignment, and I don't agree that having to write
different code for logic vs non-logic semantics is a significant obstacle.
In practice, you still have to write different code in Oz for even
slightly more complicated examples, such as the deterministic vs
don't-know- nondeterministic versions of Append that Russ Abbott pointed
out.

Having to write different code for sequential vs concurrent semantics
would be an obstacle, but no language that supports delayed references
requires that, AFAIK.

In any case, the point I was trying to make about having distinct
declarations for delayed references vs mutable variables, is independent
of whether delayed references are implicitly bound by unification. It is
quite possible for a language to have delayed references that are bound
by unification but have to be declared differently from other variables.

In Oz, the syntax that is used to declare the equivalent of a mutable
variable (e.g. "local X = {NewCell 0} in ...") forces some value to be
specified as the initial cell contents, even when it would be more natural
to initialize the contents later. This hides errors that in Java, and
potentially in a language that forces dataflow and mutable variables to
be declared using different syntax, would be diagnosed at compile time.

> There's other patterns that are possible, but these are off the top of
> my head.  IIRC, CTM covers all the bases in one of the chapters. 
> Anyhow, futures can be used to get a lot of the effect, but there is a
> bit of manual processing that has to go on to get unification to work. 
> The advantage of Oz is that a function can be written in such a way as
> to be automatically concurrent and logic enable.  You don't have to have
> one function written without futures for non-concurrent processing and
> one written with futures to get concurrency (dataflow processing makes
> the code equivalent).

"Automatic concurrency" and "automatic logic semantics" are different
issues. One of the unusual aspects of Oz related to its "automatic logic
semantics" is that it passes parameters by unification, which has some
disadvantages. But this post is already too long, so I'll discuss that
separately.

-- 
David Hopwood <[EMAIL PROTECTED]>


_________________________________________________________________________________
mozart-users mailing list                               
[email protected]
http://www.mozart-oz.org/mailman/listinfo/mozart-users

Reply via email to