new syntax - a provocation
Joe Armstrong
joe@REDACTED
Tue Sep 23 10:42:46 CEST 2003
On 23 Sep 2003, Mike Williams wrote:
> The best way to "kill" a language is to make continuous additions.
> If people believe a language is in the process of change, they
> won't use it. The problem is not the additions per se, it is that fact
> that it is very hard to remove older, often not so well thought out,
> constructs. For example I would very much like to see "catch/throw"
> removed, I would like to remove "records" and replace them with some other
> construct. But this would break a huge amount of existing code.
> Every addition will make Erlang biger and more cumbersome to learn and
> use.
Yes - but ...
We got a lot of things wrong in Erlang and a lot of things right - changing
the language because we got things wrong is IMHO a good idea.
Now a few comments:
1) Changes should add power to the language *and* make it simpler
we want fewer constructs that are more powerful NOT lots of special
cases.
My "wish list" has several things (and not of them
are changes to guards :-) - Here is a brief list and explanation.
Stuff in <<...>> are comments (possibly not well thought out)
- Higher order code
<< This is "thinking out loud - ..."
something like
I think a module should be defined thus:
SrcMod = {{export,
[{foo,2,fun(I,J) -> ... end},
{bar,1,fun(I) -> ... end},
]},
{private,
[{boo,3,fun(I,J,K) -> ...]}}},
Mod = compile(SrcMod),
Mod:foo(1,2) ...
install(Mod, quack)
quack:foo(1,2)
Src1 = replace(foo,2,Mod, fun(I,J) -> ...)
...
Then I'd like not TWO but an indefinite number of "old
versions" of the code - let the GC remove code that is
not reachable.
>>
- Proper structs
<< junk the record stuff. thus has been discussed in previous
mails >>
- remove the atom table.
<< The *easiest* way to do "Atom table GC" is not to have an atom
table in the first place - redesign Erlang so that it does not
need an atom table - this is "relatively" easy >>
- Increase the "isolation" properties of processes
<< I want better inter-process protection. One process should not
be able to crash another though a side effect, like
flooding the process with messages.>>
- Integrate Erlang I/O system with my ideas on UBF - ie
make strong contractual obligations on the kind of
session dialogs that one Erlang system can have with another.
2) We have to distinguish the *essential* features of Erlang from
the non-essential.
IMHO the *essential* features are:
- light weight concurrency
- inter-process isolation
- transparent distribution
- remote detection of errors
All the rest (HOFs, structs, List comprehensions, type systems,
bit syntax, macros, includes, ... bla bla) are "nice to have"
but NOT essential.
IMHO the most essential of the essential features is "isolation".
Operating system processes do two things - they allow transparent
resource sharing (like CPU time slicing) and protection.
One process cannot muck around with another processes. To me this
is the *essential* feature of a processes. It allows us to protect
one body of code from another - it allows groups of people to
write code. Without this protection any error in any code could crash
the entire system.
Since most languages (java, C++, C, .....) do not have any notion
of protection they cannot be used for any large bodies of code in a
reliable manner (well they *can* be - but it is very difficult).
Process provide "protection domains" - unfortunately OS processes
are big and heavy (they don't have to be - <<in some (rare) Os's
there are light-weight processes>> but in the dominant unix/windoze OSs
processes are heavy>>
Because processes are big and heavy, the notion of "threads" emerged
(threads share resources) and are lighter weight than processes -
but oops - out went the baby with the bath water. We lost protection -
wow - great - fantastic - super - wooppee - not we can write
super duper fast programs which crash the system - joy.
Enter Erlang/Oz, ... whose processes are lighter-weight than
threads AND have the protection (but not quite - I suspect
that OS processes are better protected than Erlang processes).
IMHO we need to modify Erlang to increase the isolation properties.
3) On language implementations.
All these nice things that people want are a *pain* for the
implementor. A small number of very general things is easier to
implement than a lot of special cases.
The last ten years of Erlang development have followed the
"make it faster" track - ie keep the language the same but make it
faster.
The "make it slower" track has been ignored.
Where is the "pessamizing compiler?" - Personally I am interested in
the "very small, very easy to understand - very easy to port" -
very well documented" type of implementation.
I have been re-working the system with this in mind.
Here all the things that make the programmer's life easy make
my life a pain.
Erlang variable scoping rules are, for example nice for the user
but a pain for the compiler writer.
As regards a simple implementation I am of two minds here -
I have a very nasty case of "can't make my mind up" ism - here
are two approaches:
A) Transform to a kernel language and then do an
efficient (yes I said it :-) compilation of the kernel language.
<<ie transform out cases, if, func, lc, records into kernel Erlang
and compile what's left>>
B) Compile everything in-place.
ie let the kernel compiler know about cases, funs etc.
So far I'm doing B) - but the B approach involves a virtual machine
which has specialized instruction for handling closures,
list comprehension iterators etc - the nice language features
that we all want to have can be either rather easy or very difficult
to implement at this level.
I guess A) might be better - but would it be sufficiently
efficient - compiling out cases, ifs etc. lambda-lifting, and "list
comprehension lifting"
(is their such an expression) results in many extra function calls
and a lot of additional argument shuffeling on the stack or in
registers.
I guess the real answer is "do it both ways and measure" ... :-(
<<In any case I think a code-to-kernel transformer is pretty
useful ... - and yes I know there *is* a kernel form -
but even it is is rather too complex for my taste - I'm
thinking more of the pure lambda calculus augmented with
processes >>
>
> So please, if we want Erlang to spread, let's keep the language stable
> and have a moratorium on new constructs, new bif's etc.
No - do the right thing (TM)
I think the right thing is to *remove* non-essential stuff and
build on the central core concepts -
Increase the isolation property of processes.
This makes Erlang more useful.
/Joe
>
> /mike
>
>
> In article <Law12-OE52BXx4XFKpR00001991@REDACTED>,
> you write:
> |> Hi,
> |>
> |> Since new syntax constructs have been discussed, I have some ideas that I'd
> |> like to present here. The intention is to spur some more ideas, and maybe
> |> some will find a growing ground.
> |>
> |> * I have found myself wishing to be able to build data structures other than
> |> tuples or lists, in the same elegant way as tuples and lists, directly in
> |> the code. The most acute need was for bitsets/integer sets, where using the
> |> binary syntax is very cumbersome when there are many such sets to be
> |> declared. It would be super-nice to be able to write something like
> |> #[0011010001]
> |> or
> |> &[3, 45, 27, 39],
> |> where the first is a bit representation, and the latter a set containing the
> |> specified integers. The implementation would be as binaries, so just the
> |> syntax is new.
> |>
> |> * I thought this could be solved with a parse transform, but I think the
> |> lexer should be able to cope with new tokens too, since overloading existing
> |> ones would only make a mess out of it. That's why I thought "why not
> |> introduce something similar to Lisp's reader macros?" We could have a
> |> special char (for example, @) to use in constructs like
> |> @[....]
> |> that will be transformed into something like (in this case)
> |> mylexer:'['(....)
> |> and evaluated at compile time into "real" Erlang.
> |>
> |> * Having come this far, and remembering Tobbe's (I think) call for Erlang2,
> |> and also Luke's Lisp parallels, there is one more small step to take, for
> |> those that like to play on the edge: Why not replace the whole Erlang syntax
> |> to a more Lispy one? (or more correctly, closer to CoreErlang) A
> |> different-looking language, but the same BEAM code and runtime. There are
> |> many aspects of such a syntax that add plenty of power to Lisp, why not use
> |> that power?
> |>
> |> Note: I am too aware of some of the (many) downsides. I tried to be a little
> |> provocative by leaving them out, and also any examples and possible
> |> advantages.
> |>
> |> regards,
> |> Vlad
> |>
>
More information about the erlang-questions
mailing list