[erlang-questions] Was Re: Bug ?! now Erlang comment (LONG LONG)
Robert Virding
robert.virding@REDACTED
Mon Oct 16 23:43:32 CEST 2006
Thomas Lindgren wrote:
>
> --- Robert Virding <robert.virding@REDACTED> wrote:
>
>
>>I believe it is important to keep things clean,
>>consistent and elegant
>>otherwise you will end up with a language built on
>>exceptions.
>
>
> So what is your opinion on Erlang of today? (half :-)
>
> Best,
> Thomas
I have been debating with myself whether to answer this but in the end I
gave in and decided that I would.
Omn the whole I think we got things right but there are some things
which are wrong. Some are new, some are old and some are even my fault.
:-) So here is a collection of comments, major and minor (major marked
with +):
- The naming and argument orders of the standard libraries is
inconsistent. While this can seem trivial it does break the principle of
least astonishment and therefore causes unnecessary problems.
- The syntax could have been cleaned up a bit. No, I don't see any
problems with having ';' as separator not a terminator. Being able to
write "foo(X) -> X;." sucks.
+ Should have had proper variable scoping, what is right for Prolog is
not best for Erlang. I would also have all variables in patterns as
fresh variables and have explicit tests for equality with already bound
variables.
+ The concept of what a BIF (Built In function) is is a mess. Now it
seems to mean something written in C. That is something we addressed in
the standard and got right. A BIF is a function which is part of the
langauge but without special syntax. So spawn and link are just as much
Erlang as ! and receive but they look like functions. BIFs have the same
dignity as the emulator, both ARE the language.
What language a BIF is written in is irrelevant.
Most BIFs can be called through the module erlang so having the module
erlang as part of OTP just does not make sense.
- Some of the BIF names are too long, tget and tset would have been better.
- A suggestion in the standard was to have BIFsin different modules not
just erlang, for example atom, tuple, number, proc, ... This would have
been much better and could have been added with a minimum of trouble.
+ There is no layering in the standard libraries, all is part of OTP.
This make is difficult to build small, stand-alone application. In
essence you tend to get what OO was accused of: you want the banana but
get the whole gorilla as well. Yes, you can make a tool which extracts
what you want but that is a work-around not a fix.
Many of the libraries are so fundamental that having them managed by OTP
does not really make sense, they are below that necessary for it.
Joe and I discussed this alot and we agreed on the principle but not on
all the details. I would like to see something like:
____________________________________________________________________
erlang emulator + BIFs (see above)
____________________________________________________________________
basic libraries - lists, file, io etc. (maybe layered as well)
____________________________________________________________________
|
OTP | included applications - compiler, etc |
_________________________________________________
user apps, OTP based or otherwise
____________________________________________________________________
The system is useable without OTP and applications can choose at what
level they need the libraries. I hope the diagram is understandable.
- Binaries are nice but I don't really like the bit syntax, although I
haven't really sat down and come up with a better alternative.
- Records as they stand are not beautiful. However, it is important to
remember that when they were introduced it was an absolute requirement
that they would be as fast as using tuples directly. Even this
implementation was suspect. I kid you not.
- Structs or dictionaries as suggested by Richard O'K would be a BIG WIN.
+ All forms of communication between processes should be asynchronous.
Messages signals, links, ALL of them. You send them off and depending on
what you do you may get an exit signal back. Originally the only thing
which broke this principle was sending to a local registered process,
now, however, more things break it. Link for example.
Why worry you may ask. Well, everything which is asynchronous will
automatically scale to distributed systems, synchronous calls don't!
This may also affect multi-core implementations which are going to be
very important.
+ Originally there were two basically different types of objects in
Erlang: static terms and things with dynamic state, processes.
A process is something which has process semantics, you communicate
through messages, can link to it and exchange exit signals. N.B. how a
process is implemented is irrelevant it is the external semantics which
define a process.
Unfortunately there two (at least) things in erlangwhich don't conform
to this principle, ETS tables and ports. They're coming next.
+ ETS tables are neither and this causes problems. ETS was conceived to
solve two main problems: fast, near constant access to large tables; and
to get around the garbage collection problem in the erlang
implementation. If you have a LARGE process then it is noticeable when
the emulator stops during a collection. This problem still exists today.
The solution to the second problem was to keep ETS tables in a
completely separate area and copy data to/from processes. Unfortunately
this implementation detail, which it is, affected the interface and
instead of solving the real problem, i.e. the copying, work-arounds were
added to minimise this, match_XXXX, select_XXXX, ms_transforms. No one
can claim that match patterns and matchspecs are beautiful or fit in
with the rest of erlang. These are just work-arounds to minimise copying
and would be unnecessary if the implementations was fixed. Then you
could use a proper pattern to select and all you would need is fold.
Getting back ETS tables are neither static data or processes and break
the principle.
+ Ports are funny. Originally when they were conceived they had only
process semantics, in fact we actually debated whether to have a
separate data type at all. They were modelled on UNIX streams, the idea
being that you could insert various filters along the way without the
users noticing. This is no problem with processes.
However, the the various port_XXXX commands were added and now ports are
different. Ironically, the manual calls the process interface illogical
because it is different from the function interface.
- if should really have been what cond is today. Is cond today?
- The abstract form of the erlang syntax should have been in a form
which could be described by records.
- and/or and andalso/orelse are different semantically and having both
is a win, although some people don't think so.
- catch should not have been an operator but instead catch ... end.
- Erlang does not need currying.
- Erlang was originally designed to follow the KISS principle.
+ Perhaps we should have defined the message interface more often
instead of wrapping everything in an access function? You can do more
with the interface.
+ You need both link and monitor_process, it would have been better to
have a more basic primitive on which both are built. Easier to under
stand the interactions.
Having everything consistent makes it easier to understand and lessens
the risk of strange interactions. If everything is a process and obeys
the (asynchronous) process semantics then it easier to understand the
interactions. They will all be explicit in the code (even the mistakes
:-)) and not so dependant on which order you do things because sometimes
you get a fault and sometimes a signal so if they are in the wrong order
then somethings won't get done.
Special cases just cause problems in the long run.
That's about it for the first go. I will willingly debate any of my
comments on the erlang, but don't expect me to change my mind. Being, as
I am, right.
Robert
"I'm not arrogant, I'm right!"
More information about the erlang-questions
mailing list