Joe Armstrong <>
Tue Jun 4 10:56:14 CEST 2002

On Mon, 3 Jun 2002, C.Reinke wrote:

> > > A more lightweight syntax for funs would make that a lot nicer, of
> > > course, and "do" might not be the most suggestive name, but it
> > > avoids names for intermediates as well as language extensions..
> > >
> > > Btw, why can't variables be passed unbound to functions (that
> > > would make more complex utilities easy)?
> > 
> > I think you have invented monads AND dataflow variables  :-)
> Hey, you can't blame me for everything, you know!-)
> Btw, I explicitly avoided monads, because with Erlang's heavy-weight
> syntax, they would look even less usable than the more primitive
> compose-a-list-of-funs definition I suggested.
> > This is *very* difficult to implement :-)
> You wouldn't by any chance know whether that's why Erlang's
> designers chose not to have it in the language?-) 

 Erlang grew out of Prolog - firstly by adding a notion of processes, secondly
by adding mechanisms for fault-tolerance and hot code swapping.

  Erlang is  *basically* a  concurrent language -  it was  designed to
have  fast process  spawning,  context switching  and message  passing.
Anything that  worked on one  processor should work in  a distributed
system with minimal changes to the program.

  The sequential part of Erlang  was just a simple functional language
- any language could  do I guess, the fact it  was functional was more
or less an  accident it could equally well have  been an imperative or
logic language (provided it was garbage collected :-).

  We deliberately  stayed clear  of *anything* that  involved "dangling
references",  we  didn't want  messages  between  machines to  contain
pointers, so  we insisted that messages were  copied between machines.
This  was because  we  wanted the  system  to work  reasonable in  the
presence of  machine failures  and we wanted  message passing  to have
transaction  semantics  (i.e.   all  the message  gets  transfered  on
nothing) - In the *language*  we want to create loosely coupled systems
without strong data bindings between data components.

> Instantiation of "logical" variables used to be the standard means
> of communication between and-parallel threads in the various
> non-sequential prologs (5th generation, etc.), and is still not
> dead for logic-based concurrent calculi. But you know that
> because you looked at many of those before and during the evolution 
> of Erlang, and the mailbox/send/receive-model has proven to be
> practical (so far, more practical than 5th gen ideas;). 

  We rejected stream communication with  logic variables - there are a
few problems with this.

  - out of order messages can cause deadlocks.
  - setting up the splitter/merger networks to get the right streams the
    the right places is messy 
  - code is more difficult to understand (this is subjective). i.e.
    message passing can be achieved "invisibly" just by binding a variable.

>   [it shouldn't be difficult to define a naive variant of a
>   distributed single-assignment construct on top of Erlang's
>   mailboxes: a thread with mailbox receives assignments from 
>   writers and answers with success (first write commits) or 
>   failure (consecutive incompatible write attempts); 
>   synchronization of writers (all fail or all succeed) would
>   be more difficult; Erlang didn't inherit non-deterministic
>   user-defined rules, so dealing with or-parallelism is not
>   an issue - hmm, could that be modeled via supervisors?-]

  I think this would be valuable in a library module. It would be
nice to have a library that did something like:

	NewVar = logic_var:create()   % create a logic variable

	Pid ! ... NewVar ...          % you can send it *anywhere*

	logic_var:bind(Var, Value)    % bind it
				      % returns a boolean
				      % true if you were the first to bind it
				      % false otherwise

	logic_var:send_message(Pid, Var) % send Pid a {bound,Var,Val}
					 % message when Var is bound

        (This is give an Erlang flavor to things)

	logic_var:wait(Var)           % wait for Var to be bound

   *then* you could write things like

	V = new_var(),
	Pid1 ! Pid2 ! Pid3 ! Pid4 ! {who_wants_to_buy_my_car_for_10_dollars, V}


   Now make my day and tell me that somebody has already written this.
[tricky bit - what happens when remote nodes crash ...]

> I wasn't suggesting to go back to that (well, at least not for
> Erlang), but banning unbound variables from function calls might
> be overly restrictive (given the, now remote, relation to prologs).
> Why not permit unbound variables in function calls, and only outlaw
> them in inter-thread communications? 

  Because we want things to work the same way in *all* circumstances.

> I looked at logic vs functional
> languages a while ago, and most of the examples where logic
> languages won where down to this late, but still single-assignment
> use of variables. And its a lot easier (almost trivial?) to
> implement within thread-boundaries.

> > Then we send the unbound variable to two *different* processes - imagine
> > they are on different machines (just to make it more fun).
> > 
> > They now both try to bind X at the same time :-) - one should succeed
> > the other should fail - and it should work in the presence of errors ...
> > 
> > << this is what Oz does (see >>
> It's been a long time since I visited Oz;) but the general ideas
> go back a lot farther (though I don't recall to what extend those
> early parallel "logic" languages dealt with distribution, as in Oz).

  Oz was designed after Erlang. The Oz group had previous done a lot
of work with parallel prolog dialects.

  Interestingly  -  we  can  discern  a  Swedish  school  of  parallel
programming - the "processes in  the language" school - to this belong
(Erlang,  Oz,  Eri-pascal,  PLEX).  Most programmers  (I  think)  view
processes as "operating system things" NOT "language things".

  Processes in most languages are  not processes but threads - and the
threads are a thinly disguised layer over the OSs threads.

  Threads  are claimed  by  some to  be  "light weight"  - but  Erlang
processes  are (say) 100  times faster  to create  & destroy  than the
appallingly bad Java or C# threads.

  The fact  that (say) java threads  are so badly  designed (and green
threads so appallingly implemented) gives the whole idea of concurrent
programing a bad name.

  The  Erlang/Oz  school  is  more  about  concurrency  than  FP/logic
programming  - the  trade-offs  in the  Erlang  design decisions  were
always to make sure the languages were good at concurrency - and *not*
that it  was a fully fledged  FP languages. FP  was essential "bolted
onto" a concurrent language - not the other way round.

  In Java/C#/C++ and the concurrent  dialects of the popular FPs it is
the  other way  round  - concurrency  is  added as  an afterthought  -
usually as a thin layer to OS threads. That's why threads suck in most
languages - because they were added as an afterthought. Try creating
1000 parallel threads in C# on windows 2000 - (joke)

  Sorry - I rambled off subject here ...

  I am becoming  more and more convinced that  Erlang should be judged
as a concurrent language than as an FP langauge.

  If you  compare Erlang *as  an FP* it  may or may not  be marginally
better  than Haskell,  ML, ...  If it  is better  (or worse)  then the
difference is marginal.

  If you compare Erlang as a *concurrent* langauge with Java/C#/C++ is
is  a  *lot*  better -  it  is  not  marginally  better -  the  *only*
discussion here  is "are we 100  times better or 1000  times better at
process handling that Java threads?



> Cheers,
> Claus
> PS. I notice two aspects of Erlang that tend to aggravate the 
>     problem discussed in the original thread (beyond the problems
>     most functional languages used to have with this):
>     - non-nesting variable scope (fortunately not adopted for
>       the higher-order extensions)
>       so one cannot reuse the same variable name, as one usually
>       can with non-recursive lets.
>     - relatively heavy-weight syntax
>       making the use of higher-order functions less convenient
>       than in Haskell (MLs have the same problem). So instead
>       of defining their own higher-order control constructs
>       (which otherwise tends to be home ground for functional 
>       languages), people are asking for language extensions 
>       (the same happened with behaviours).

More information about the erlang-questions mailing list