So now all I'd like in Erlang is...

classic Classic list List threaded Threaded
22 messages Options
12
Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

James Hague-3
Joe Armstrong wrote:

>So now all I'd like in Erlang is:
>
>1) Higher order code

Could you elaborate?

>2) *Proper* structs

Has any progress been made toward this one?  At least some internal
political discussion at Ericsson? :)

>3) !!
>4) Higher order receive
>5) A *tiny* implementation (written 99% in Erlang and 1% in ANSI standard
C)

How tiny do you want to go?

If nothing else, I'd like to see most of the BEAM opcode combination stuff
in beam_load.c be rolled into the compiler.  This would be a big win in
terms of reducing complexity.

James


Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Vlad Dumitrescu-4
From: "James Hague" <jamesh>
> Joe Armstrong wrote:
> >So now all I'd like in Erlang is:
> >1) Higher order code
> Could you elaborate?

Yes, please!

> >3) !!

How could we have timeouts with "!!"?

> >5) A *tiny* implementation (written 99% in Erlang and 1% in ANSI standard
C)

I feel this should mean removing the 'query' reserved keyword and
Mnemosyne-query LCs from the "regular" parser/compiler, and implementing
them as extensions in a general way. Or?

/Vlad



Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Joe Williams-2
In reply to this post by James Hague-3
On Tue, 17 Feb 2004, James Hague wrote:

> Joe Armstrong wrote:
>
> >So now all I'd like in Erlang is:
> >
> >1) Higher order code
>
> Could you elaborate?

First order code is code that I can manipulate as regular data.

I'd really like a do thinks like this ...

        % define a module
        Mod = {{export,[{foo,2},{bar,1}....]},
               {code, [{foo,2,fun(X,Y) -> ...end},
                       {bar,1,fun(X) -> ... end}]}},
        % compile it
        Code = compile(Mod),
        % call code without "publishing it"
        Code:foo(1,2)
        % publish it
        publish(Code, bar),
        % now you can use it
        bar:foo(1,2), ...
        % modify it
        Code1 = replace_fun(Code, foo,2,fun(X,Y) -> ... end)
        % test it
        Code1:foo(1,2)
        % publish
        publish(Code, bar)
        % ...
        % get the code back
        Code2 = getCode(bar)
        ...

        GC should sweep away unreachable code

        There should be multiple versions of old code (not just two)

>
> >2) *Proper* structs
>
> Has any progress been made toward this one?  At least some internal
> political discussion at Ericsson? :)
>
> >3) !!
> >4) Higher order receive
> >5) A *tiny* implementation (written 99% in Erlang and 1% in ANSI standard
> C)
>
> How tiny do you want to go?
>
  Without any space allocated for processes I'd like the run-time down to
less than a 500KB - a decent app should be less than 1 Meg.

> If nothing else, I'd like to see most of the BEAM opcode combination stuff
> in beam_load.c be rolled into the compiler.  This would be a big win in
> terms of reducing complexity.

  I am current playing with the idea that one should "write as much in
Erlang as  possible and  write as  little C as  possible" and  also if
possible write  a program  to write  the C rather  than writing  the C
myself.

  I am experimenting with a code generator, you give it rules like this:

        {{pushAtom, a}, {opCode, i}, "*Code++ = &&Opcode;
                           *Code++ = *codeBuff++;"
               
         "*Stop++ = *PC++;"}

  This means there is an instruction pushAtom with argument an Atom to
serialize it generate an opcode followed by an integer. To deserialise
it and make it into threaded code evaluate *Code++=...  and to execute
execute do "*Stop++ = ..." etc.

  My code generator splits out chucks  of C and Erlang which get glued
together to make the back-end  of the assembler and the input routines
for deserialising the data and the inner loop of the the emulator.

  It is my  hope that even tricky  things like GC can be  written in a
combination of C and Erlang.  I can imagine Erlang (say) administering
the GC sweeps and making policy  decisions about when to do GC etc and
just write a single process  stack/heap collector that is triggered by
the Erlang process.

  Writing C is like performing open brain surgery - it seems easier to
write programs which write C rather  than writing it myself - that way
you  only have  to get  the code  generator right  *once*  rather than
getting every single C program right.

  /Joe


  > > James >



Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Tony Rogvall-3

On Tuesday, Feb 17, 2004, at 20:43 Europe/Stockholm, Joe Armstrong
wrote:

> On Tue, 17 Feb 2004, James Hague wrote:
>
>> Joe Armstrong wrote:
>>
>>> So now all I'd like in Erlang is:
>>>
>>> 1) Higher order code
>>
>> Could you elaborate?
>
> First order code is code that I can manipulate as regular data.
>
> I'd really like a do thinks like this ...
>
> % define a module
> Mod = {{export,[{foo,2},{bar,1}....]},
>       {code, [{foo,2,fun(X,Y) -> ...end},
>       {bar,1,fun(X) -> ... end}]}},
> % compile it
> Code = compile(Mod),
> % call code without "publishing it"
> Code:foo(1,2)
> % publish it
> publish(Code, bar),
> % now you can use it
> bar:foo(1,2), ...
> % modify it
> Code1 = replace_fun(Code, foo,2,fun(X,Y) -> ... end)
> % test it
> Code1:foo(1,2)
> % publish
> publish(Code, bar)
> % ...
> % get the code back
> Code2 = getCode(bar)
> ...
>
> GC should sweep away unreachable code
>
> There should be multiple versions of old code (not just two)
>
I have implemented this once, in the (in)famous Multi Pro Erlang.
It worked like a charm.
I also thought a bit of adding functionality to upgrade code in generic
servers by using
"unpublished" code.
The implementation overloaded register and unregister instead of
publish/unpublish, it used a new
dynamic type "Module" to distinguish the cases. Of course the Module
had a external representation
as any Erlang Term so loading code and register looked like.

        {ok, Bin} = file:read_file("mymod.beam"),
          Mod = binary_to_term(Bin),
          register(mymod, Mod).

In a multipro environment the register part was a bit tricky but we (me
and Pekka H) think we
solve it.

.......

>
>   I am current playing with the idea that one should "write as much in
> Erlang as  possible and  write as  little C as  possible" and  also if
> possible write  a program  to write  the C rather  than writing  the C
> myself.
>
>   I am experimenting with a code generator, you give it rules like
> this:
>
> {{pushAtom, a}, {opCode, i}, "*Code++ = &&Opcode;
>            *Code++ = *codeBuff++;"
>
>          "*Stop++ = *PC++;"}
>
>   This means there is an instruction pushAtom with argument an Atom to
> serialize it generate an opcode followed by an integer. To deserialise
> it and make it into threaded code evaluate *Code++=...  and to execute
> execute do "*Stop++ = ..." etc.
>
>   My code generator splits out chucks  of C and Erlang which get glued
> together to make the back-end  of the assembler and the input routines
> for deserialising the data and the inner loop of the the emulator.
>
>   It is my  hope that even tricky  things like GC can be  written in a
> combination of C and Erlang.  I can imagine Erlang (say) administering
> the GC sweeps and making policy  decisions about when to do GC etc and
> just write a single process  stack/heap collector that is triggered by
> the Erlang process.
>
>   Writing C is like performing open brain surgery - it seems easier to
> write programs which write C rather  than writing it myself - that way
> you  only have  to get  the code  generator right  *once*  rather than
> getting every single C program right.
>
(CRAZY IDEA SECTION)
Ok what about Forth, the forth has the tiny interpreter (talking about
a few bytes). I have had a project
that has been in my mind for years. That  is to rewrite the erlang
runtime system in forth
(yes I have written a forth system capable of such a task).
Then let the erlang compiler generate forth (in some nice loadable
format).
When loading such a module a range of transforms (even jit assembler
stuff is available)
(I do however think that this require an even bigger brain surgery than
writing C code :-)

Forth is truly mind boggling

/Tony



Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Shawn Pearce
In reply to this post by Joe Williams-2
Joe Armstrong <joe> wrote:

> I'd really like a do thinks like this ...
>
> % define a module
> Mod = {{export,[{foo,2},{bar,1}....]},
>       {code, [{foo,2,fun(X,Y) -> ...end},
>       {bar,1,fun(X) -> ... end}]}},
> % compile it
> Code = compile(Mod),
> % call code without "publishing it"
> Code:foo(1,2)

I've often wondered why Erlang code is:

        foo(X) ->
                ok.

and not:

        Foo = fun(X) ->
                ok
        end.

with call sites using:

        Foo(x).

instead of:

        foo(x).

In other words, why are named functions different from lambdas?  Why
not make all named functions actually global variables which are
assigned to a lambda when the module loads?

As soon as you do this, it becomes possible to do things like:

LoadDetsFile = fun() -> ... pull a dets file into a list .. end.

SomeConstant = LoadDetsFile().

LookupUser = fun(Name) ->
        Lists:Keysearch(Name, 1, SomeConstant)
end.

:-)

> There should be multiple versions of old code (not just two)

Yippee!  With this we can get rid of that *killed* message I love
so much when you load the module twice and your servers are plain
Erlang servers which are wedged in a receive call.  :-)

And I can blow up memory footprint by loading modules every few minutes
and never getting the existing processes to switch to the new version.
Oh, that's what I do in Java at work.  :)

This I think is a really good thing.  It removes some risk associated
with code upgrades, and upgrading too quickly.

>   Without any space allocated for processes I'd like the run-time down to
> less than a 500KB - a decent app should be less than 1 Meg.

Wow.  That would be sweet if the runtime could get that small.  I
think only a handful of programs, like say agetty on Linux, run in
that tiny of a heap anymore.

>   Writing C is like performing open brain surgery - it seems easier to
> write programs which write C rather  than writing it myself - that way
> you  only have  to get  the code  generator right  *once*  rather than
> getting every single C program right.

This is why I try to write Java code generators, and not Java code.  I
once did an Erlang code generator in Erlang, and for whatever reason,
found it more painful than I'd like to remember...

I'm all for building a micro-Erlang with no human written C code in it
at all.  :-)

--
Shawn.

  Once you've tried to change the world you find it's a whole bunch easier
  to change your mind.


Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Björn Gustavsson-3
In reply to this post by James Hague-3
James Hague <jamesh> writes:

> Joe Armstrong wrote:
>
> >So now all I'd like in Erlang is:
> >
> >1) Higher order code
>
> Could you elaborate?
>
> >2) *Proper* structs
>
> Has any progress been made toward this one?  At least some internal
> political discussion at Ericsson? :)

Yes, we have discussed it.

Joe's ideas for structs are good, but we are very careful with actually
starting to implementing it, because we must essentially get everything
right the first time. People will start using struct immediately and it
will be very hard to go back and change anything.

The issues that I see with structs are that they will be slower than
records, at least for read access. Therefore, they may not be usuable in
all circumstances where records are used today.

>
> >3) !!
> >4) Higher order receive
> >5) A *tiny* implementation (written 99% in Erlang and 1% in ANSI standard
> C)
>
> How tiny do you want to go?
>

I don't see the point with having a tiny implementation.

Most important for our customers are stability and speed. If that makes
the implementation more complex (and it does), that's OK.

However, we don't want NEEDLESS complexity. Some things are still too
complicated, and we are working on reducing needless complexity and removing
options that are not used. Unfortunately, having to be backwards compatible
prevents us from making all changes we want.

> If nothing else, I'd like to see most of the BEAM opcode combination
> stuff in beam_load.c be rolled into the compiler.  This would be a
> big win in terms of reducing complexity.

I doubt that.

The Beam loader is certainly complex, but it is complexity isolated in
a single place.

Having the loader there keeps the compiler simpler, and allows us to keep
the beam file format compatible. Essentially, the format is the same from
R5B up to R10B and beyond. (In practice, a few minor details prevent you from
loading and running most R5B modules in R9B and higher, but you can always run
code compiled several releases back.)

/Bjorn
--
Bj?rn Gustavsson, Erlang/OTP, Ericsson AB

This communication is confidential and intended solely for the addressee(s). Any unauthorized review, use, disclosure or distribution is prohibited. If you believe this message has been sent to you in error, please notify the sender by replying to this transmission and delete the message without disclosing it. Thank you.

E-mail including attachments is susceptible to data corruption, interruption, unauthorized amendment, tampering and viruses, and we only send and receive e-mails on the basis that we are not liable for any such corruption, interception, amendment, tampering or viruses or any consequences thereof.



Reply | Threaded
Open this post in threaded view
|

Erlang + Forth?!?

Michał Ptaszek
In reply to this post by Tony Rogvall-3

Good Lord! I had forgotten that remarkable language!

I have never used it, but over 20 years ago I pondered buying a Jupiter ACE instead of a Sinclair Spectrum, but was beguiled by the spectrum "colour" capability. Young fool! (-:

Has anyone heard of or remember the Jupiter ACE, made by Jupiter Cantab? It was the only interesting competitor of the Sinclair ZX Spectrum in the 1980's, and it's native language was forth, not BASIC. It beat the pants off the competition in terms of pure speed.

Pete.


On Tue, 17 Feb 2004 22:55:09 +0100
Tony Rogvall <tony> wrote:

>
> On Tuesday, Feb 17, 2004, at 20:43 Europe/Stockholm, Joe Armstrong
> wrote:
>
> > On Tue, 17 Feb 2004, James Hague wrote:
> >
> >> Joe Armstrong wrote:
> >>
> >>> So now all I'd like in Erlang is:
> >>>
> >>> 1) Higher order code
> >>
> >> Could you elaborate?
> >
> > First order code is code that I can manipulate as regular data.
> >
> > I'd really like a do thinks like this ...
> >
> > % define a module
> > Mod = {{export,[{foo,2},{bar,1}....]},
> >       {code, [{foo,2,fun(X,Y) -> ...end},
> >       {bar,1,fun(X) -> ... end}]}},
> > % compile it
> > Code = compile(Mod),
> > % call code without "publishing it"
> > Code:foo(1,2)
> > % publish it
> > publish(Code, bar),
> > % now you can use it
> > bar:foo(1,2), ...
> > % modify it
> > Code1 = replace_fun(Code, foo,2,fun(X,Y) -> ... end)
> > % test it
> > Code1:foo(1,2)
> > % publish
> > publish(Code, bar)
> > % ...
> > % get the code back
> > Code2 = getCode(bar)
> > ...
> >
> > GC should sweep away unreachable code
> >
> > There should be multiple versions of old code (not just two)
> >
> I have implemented this once, in the (in)famous Multi Pro Erlang.
> It worked like a charm.
> I also thought a bit of adding functionality to upgrade code in generic
> servers by using
> "unpublished" code.
> The implementation overloaded register and unregister instead of
> publish/unpublish, it used a new
> dynamic type "Module" to distinguish the cases. Of course the Module
> had a external representation
> as any Erlang Term so loading code and register looked like.
>
> {ok, Bin} = file:read_file("mymod.beam"),
>           Mod = binary_to_term(Bin),
>           register(mymod, Mod).
>
> In a multipro environment the register part was a bit tricky but we (me
> and Pekka H) think we
> solve it.
>
> .......
>
> >
> >   I am current playing with the idea that one should "write as much in
> > Erlang as  possible and  write as  little C as  possible" and  also if
> > possible write  a program  to write  the C rather  than writing  the C
> > myself.
> >
> >   I am experimenting with a code generator, you give it rules like
> > this:
> >
> > {{pushAtom, a}, {opCode, i}, "*Code++ = &&Opcode;
> >            *Code++ = *codeBuff++;"
> >
> >          "*Stop++ = *PC++;"}
> >
> >   This means there is an instruction pushAtom with argument an Atom to
> > serialize it generate an opcode followed by an integer. To deserialise
> > it and make it into threaded code evaluate *Code++=...  and to execute
> > execute do "*Stop++ = ..." etc.
> >
> >   My code generator splits out chucks  of C and Erlang which get glued
> > together to make the back-end  of the assembler and the input routines
> > for deserialising the data and the inner loop of the the emulator.
> >
> >   It is my  hope that even tricky  things like GC can be  written in a
> > combination of C and Erlang.  I can imagine Erlang (say) administering
> > the GC sweeps and making policy  decisions about when to do GC etc and
> > just write a single process  stack/heap collector that is triggered by
> > the Erlang process.
> >
> >   Writing C is like performing open brain surgery - it seems easier to
> > write programs which write C rather  than writing it myself - that way
> > you  only have  to get  the code  generator right  *once*  rather than
> > getting every single C program right.
> >
> (CRAZY IDEA SECTION)
> Ok what about Forth, the forth has the tiny interpreter (talking about
> a few bytes). I have had a project
> that has been in my mind for years. That  is to rewrite the erlang
> runtime system in forth
> (yes I have written a forth system capable of such a task).
> Then let the erlang compiler generate forth (in some nice loadable
> format).
> When loading such a module a range of transforms (even jit assembler
> stuff is available)
> (I do however think that this require an even bigger brain surgery than
> writing C code :-)
>
> Forth is truly mind boggling
>
> /Tony
>


--
"The Tao of Programming
 flows far away
 and returns
 on the wind of morning."



Reply | Threaded
Open this post in threaded view
|

Erlang + Forth?!?

Richard Carlsson-4
On Wed, 18 Feb 2004, Peter-Henry Mander wrote:

> Good Lord! I had forgotten that remarkable language!
>
> I have never used it, but over 20 years ago I pondered buying a
> Jupiter ACE instead of a Sinclair Spectrum, but was beguiled by the
> spectrum "colour" capability. Young fool! (-:

You did the right thing, I'm sure. And you could do pretty cool
things with White Lightning Forth on the Speccy, if you wanted
to use Forth.

> Has anyone heard of or remember the Jupiter ACE, made by Jupiter
> Cantab? It was the only interesting competitor of the Sinclair ZX
> Spectrum in the 1980's, and it's native language was forth, not BASIC.
> It beat the pants off the competition in terms of pure speed.

Heard of it and read about it, yes. I think I even saw one once.
I was not surprised that it wasn't a hit, though. Forth is a lot less
friendly than Basic to a beginner. And of course, the speed advantage
was only when you compared Forth - which uses, or rather is, threaded
code - to interpreted Basic. But most interesting programs were written
in assembler anyway, and I think the Speccy was the faster machine.

(On a side note, the Spectrum Basic interpreter was made for compactness
rather than speed. The source code was just stored in a tokenized form,
and the interpreter actually used the same code both for syntax checking
and for actual interpretation, with a flag that told it what mode it was
in, i.e. "report errors" or "execute". But they did manage to cram a
whole lot of functionality into that 16k Basic ROM.)

The most interesting application of Forth that I saw in those days
was in an advanced disassembler/debugger for the ZX Spectrum. (I can't
recall the name.) It allowed you to write pieces of Forth code, to
be executed upon a breakpoint. You could thus, in a very small amount
of memory and with minimal speed penalty, do arbitrarily complicated
tests to decide whether to continue or stop, or log/print information,
etc. I don't know if there exist any other debuggers with similar
functionality.

        /Richard


Richard Carlsson (richardc)   (This space intentionally left blank.)
E-mail: Richard.Carlsson WWW: http://user.it.uu.se/~richardc/
 "Having users is like optimization: the wise course is to delay it."
   -- Paul Graham


Reply | Threaded
Open this post in threaded view
|

Erlang + Forth?!?

Bengt Kleberg-4
Richard Carlsson wrote:

>was in an advanced disassembler/debugger for the ZX Spectrum. (I can't
>recall the name.) It allowed you to write pieces of Forth code, to
>be executed upon a breakpoint. You could thus, in a very small amount
>of memory and with minimal speed penalty, do arbitrarily complicated
>tests to decide whether to continue or stop, or log/print information,
>etc. I don't know if there exist any other debuggers with similar
>functionality.
>
>  
>
when developing (part of) ose-delta, back in the early '90's, i used
this kind of feature in a debugger. but i can not remember if it was the
diab debugger or the other one (not so good compiler, green hill?).


bengt

This communication is confidential and intended solely for the addressee(s). Any unauthorized review, use, disclosure or distribution is prohibited. If you believe this message has been sent to you in error, please notify the sender by replying to this transmission and delete the message without disclosing it. Thank you.

E-mail including attachments is susceptible to data corruption, interruption, unauthorized amendment, tampering and viruses, and we only send and receive e-mails on the basis that we are not liable for any such corruption, interception, amendment, tampering or viruses or any consequences thereof.



Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Chris Pressey
In reply to this post by Shawn Pearce
On Tue, 17 Feb 2004 19:58:25 -0500
Shawn Pearce <spearce> wrote:

> I've often wondered why Erlang code is:
>
> foo(X) ->
> ok.
>
> and not:
>
> Foo = fun(X) ->
> ok
> end.
>
> with call sites using:
>
> Foo(x).
>
> instead of:
>
> foo(x).
>
> In other words, why are named functions different from lambdas?  Why
> not make all named functions actually global variables which are
> assigned to a lambda when the module loads?

How would that work w.r.t. dynamic code reloading?

-Chris


Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Shawn Pearce
Chris Pressey <cpressey> wrote:

> On Tue, 17 Feb 2004 19:58:25 -0500
> Shawn Pearce <spearce> wrote:
>
> > I've often wondered why Erlang code is:
> >
> > foo(X) ->
> > ok.
> >
> > and not:
> >
> > Foo = fun(X) ->
> > ok
> > end.
> >
> > with call sites using:
> >
> > Foo(x).
> >
> > instead of:
> >
> > foo(x).
> >
> > In other words, why are named functions different from lambdas?  Why
> > not make all named functions actually global variables which are
> > assigned to a lambda when the module loads?
>
> How would that work w.r.t. dynamic code reloading?

I think it would work just like it does now.  The only difference is
that when a module is loaded, rather than registering its exported
functions in a table, a module is actually executed.  Thus modules
are more like this (once the compiler gets done with them):

fun() ->
        code:register_module(my_module),
        SomeConstant = "this is a constant string",
        code:register_module_function(my_module, foo, fun(X) ->
                SomeConstant ++ " " ++ atom_to_list(X)
        end)
end.

Or something.  :)  The code server basically runs the module when
it loads it, allowing the other funs in that module to get put into
the symbol table, and the constants to be created.

So external calls would still resolve like they do now, its just
that the symbol table used to resolve them is built of funs rather
than functions, which are more or less like named funs, but without
environment tagging along.

Since Erlang is single assignment, the environment is ok to have, its
just constants which you want to resolve at runtime.  Each time the
module loads, the constants are reconstructed and stored in the
environments.  This might be very tough to do in implementation with
the private heap BEAM, because there is no global data...

I can think of uses like:

        PrivDir = code:priv_dir(gen_serial),
       
        open = fun(Name) ->
                open_port({spawn, PrivDir ++ "/bin/serial_esock.exe"} ...)
        end.

Would be nice to do.  Today we do:
       
        open(Name) ->
                open_port({spawn, priv_dir() ++ "/bin/serial_esock.exe"} ...).

        priv_dir() ->
                code:priv_dir(gen_serial).

Not very different at all, and equally easy to write.  Just the runtime
implications are a little different (in more ways than just
performance).  But from a semantic consistentancy point of view, I just
gotta ask the question of why are functions different from funs?  :-)

--
Shawn.

  Delay is preferable to error.
  -- Thomas Jefferson


Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Chris Pressey
On Wed, 18 Feb 2004 19:27:03 -0500
Shawn Pearce <spearce> wrote:

> Chris Pressey <cpressey> wrote:
> > How would that work w.r.t. dynamic code reloading?
>
> I think it would work just like it does now.  The only difference is
> that when a module is loaded, rather than registering its exported
> functions in a table, a module is actually executed.

OK.  There are still some problems with the approach, though.  Mainly -
how do you deal with forward references?

Even self-references in funs currently have to be done like:

  Fact = fun
    (_F, N) when N =< 1 ->
      1;
    (F, N) ->
      N * F(N - 1)
  end,
  Fact(Fact, 23).

There are at least three ways you could deal with this: you could
adopt Joe's idea for a magical this()-like BIF, or you could do some
equally magical prediction when you see "Fact = fun" and consider Fact
to be bound even within the body of the fun, or you could force the
function to be registered in the export table even if it's solely an
internal utility.

And that's just self-references.  Mutually recursive funs are even more,
uh, fun :)  They can be done, of course, but they're far from pleasant.

I guess what I'm saying is that it *would* be more orthogonal to have
all functions as funs, but even if we did, it probably wouldn't be long
before something like foo() -> bar was introduced as a shorthand for
Foo = fun() -> bar end, register(foo, Foo) anyway.

-Chris


Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Shawn Pearce
Chris Pressey <cpressey> wrote:
> how do you deal with forward references?

Uh.  Right.  Forgot about that.

> I guess what I'm saying is that it *would* be more orthogonal to have
> all functions as funs, but even if we did, it probably wouldn't be long
> before something like foo() -> bar was introduced as a shorthand for
> Foo = fun() -> bar end, register(foo, Foo) anyway.

You are definately right there.

Nice try on my part, but quite a bad idea.  :)

--
Shawn.


Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Joachim Durchholz
In reply to this post by Chris Pressey
Chris Pressey wrote:

> Shawn Pearce <spearce> wrote:
>
>>Chris Pressey <cpressey> wrote:
>>
>>>How would that work w.r.t. dynamic code reloading?
>>
>>I think it would work just like it does now.  The only difference is
>>that when a module is loaded, rather than registering its exported
>>functions in a table, a module is actually executed.
>
> OK.  There are still some problems with the approach, though.  Mainly -
> how do you deal with forward references?
>
> Even self-references in funs currently have to be done like:
>
>   Fact = fun
>     (_F, N) when N =< 1 ->
>       1;
>     (F, N) ->
>       N * F(N - 1)
>   end,
>   Fact(Fact, 23).

Oh, nice - an embryonic Y combinator :-)
(Y is a bit more general: it will take any function and "recursify" it.)

> There are at least three ways you could deal with this: you could
> adopt Joe's idea for a magical this()-like BIF, or you could do some
> equally magical prediction when you see "Fact = fun" and consider Fact
> to be bound even within the body of the fun, or you could force the
> function to be registered in the export table even if it's solely an
> internal utility.

I must be overlooking something fundamental, so please fill me in where
the error is:

Assuming the following code:

   Fact = fun
     (N) when N =< 1 -> 1
     (N)             -> Fact (N - 1)
   end,

   Fact (23)

here's my idea of what will (should, actually *g*) happen:

(Never mind the syntax, I'm simply assuming that Fact is a local variable.)

The right side of the "Fact =" assignment is a fun. Internally, that fun
is just a block of code (bytecode or machine code, details don't really
matter).
The reference to Fact is compiled into code that says: "retrieve
whatever is assigned to the name 'Fact'; crash if Fact is either
unassigned or assigned something other than a fun; evaluate parameters
and run the fun with them."
At the time that this code block is compiled, the value of Fact is not
yet known, but that's not a serious problem: it's not run at that time,
either.
The "Fact (23)" call is compiled just as the recursive call.

At run-time, things (could) happen in this order:
   * Storage is reserved for Fact
   * The fun is loaded as a constant
   * "Fact = ..." executed: reference to fun assigned to Fact variable
   * "Fact (23)" executed:
     - the fun is looked up from the Fact variable
     - the fun is called with a parameter of 23
     - inside the fun, the recursive call again looks for the fun in Fact
     - finds the same fun, calls it with 22
     - etc. until the recursion terminates

The overhead that you have is a lookup in a local variable - an
operation that's so common that it should be efficient enough :-)


So, my question is: what did I overlook?

> And that's just self-references.  Mutually recursive funs are even more,
> uh, fun :)  They can be done, of course, but they're far from pleasant.

If you handle them in Y-combinator style, then yes... but it's
straightforward: just add all the functions to the parameter list.

It's still ugly, of course, but no more ugly than a simple
self-referential function :-)

> I guess what I'm saying is that it *would* be more orthogonal to have
> all functions as funs, but even if we did, it probably wouldn't be long
> before something like foo() -> bar was introduced as a shorthand for
> Foo = fun() -> bar end, register(foo, Foo) anyway.

Actually, if my above description is correct, I'd suggest defining
   foo () -> bar
as a shorthand for
   foo = fun () -> bar
(again, just treating "foo" as a name for a local variable here, not as
an atom or anything funny).

Regards,
Jo
--
Currently looking for a new job.



Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Richard Carlsson-4

On Fri, 20 Feb 2004, Joachim Durchholz wrote:

> The reference to Fact is compiled into code that says: "retrieve
> whatever is assigned to the name 'Fact'; crash if Fact is either
> unassigned or assigned something other than a fun; evaluate parameters
> and run the fun with them."

So you want dynamic binding, like in certain Lisp dialects?

The problem with that is of course that if someone passes such a
fun into some other context where Fact is bound to something
completely different (like an integer), it dies horribly.

> > And that's just self-references.  Mutually recursive funs are even more,
> > uh, fun :)  They can be done, of course, but they're far from pleasant.
>
> If you handle them in Y-combinator style, then yes... but it's
> straightforward: just add all the functions to the parameter list.

Yes, you can do it like this:

  Odd0 = fun (0, Odd, Even) ->
               false;
             (N, Odd, Even) ->
               Even(N-1, Odd, Even)
         end,
  Even0 = fun (0, Odd, Even) ->
                true;
              (N, Odd, Even) ->
                Odd(N-1, Odd, Even)
          end,
  Odd = fun (N) -> Odd0(N, Odd0, Even0) end,
  Even = fun (N) -> Even0(N, Odd0, Even0) end

or with a single fun, like this:

  F = fun ({odd, 0}, F) ->
              false;
          ({odd, N}, F) ->
              F({even, N-1}, F);
          ({even, 0}, F) ->
              true;
          ({even, N}, F) ->
              F({odd, N-1}, F)
      end,
  Odd = fun (N) -> F({odd, N}, F) end,
  Even = fun (N) -> F({even, N}, F) end

(It's not _that_ painful...)

        /Richard


Richard Carlsson (richardc)   (This space intentionally left blank.)
E-mail: Richard.Carlsson WWW: http://user.it.uu.se/~richardc/
 "Having users is like optimization: the wise course is to delay it."
   -- Paul Graham


Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Shawn Pearce
Richard Carlsson <richardc> wrote:
> On Fri, 20 Feb 2004, Joachim Durchholz wrote:
>
> > The reference to Fact is compiled into code that says: "retrieve
> > whatever is assigned to the name 'Fact'; crash if Fact is either
> > unassigned or assigned something other than a fun; evaluate parameters
> > and run the fun with them."
>
> So you want dynamic binding, like in certain Lisp dialects?

Uhm, I don't know.  What if the following was run in parallel:

        {Foo, Bar} = {fun(X) Bar(X) end, fun(X) Foo(X) end}

ok, so its an infinite loop.  But when a fun is compiled, if the fun
could automatically assume that all variables which are going to be
bound as a result of the fun being created are also bound, as if the
had been bound before the expression?

This would make self-recursive funs easier to construct, as you would
no longer need to pass the fun to itself.

It doesn't solve the problem of forward references however.  And I think
we all agree, we'd just want the shorthand notation back, which is the
same syntax we use today.  :)

--
Shawn.

  Life is like a 10 speed bicycle.  Most of us have gears we never use.
  -- C. Schultz


Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Joachim Durchholz
In reply to this post by Richard Carlsson-4
Richard Carlsson wrote:
> On Fri, 20 Feb 2004, Joachim Durchholz wrote:
>
>> The reference to Fact is compiled into code that says: "retrieve
>> whatever is assigned to the name 'Fact'; crash if Fact is either
>> unassigned or assigned something other than a fun; evaluate
>> parameters and run the fun with them."
>
> So you want dynamic binding, like in certain Lisp dialects?

This depends on what you mean with "dynamic binding".
If you mean what I used to call "dynamic scoping", then, no, I don't
want this. I want static scoping: as soon as the "Fact" inside the
function's body is bound to a value, it should stick with that binding
for the rest of its lifetime.

But you're right that the rules have to be worded carefully to make this
case clear, and I was a bit sloppy here.

> The problem with that is of course that if someone passes such a fun
> into some other context where Fact is bound to something completely
> different (like an integer), it dies horribly.

Agreed - dynamic scoping is dangerous. Some people advocate its use for
some specific, limited circumstances (I don't, but that's just my taste
*g*).

Regards,
Jo
--
Currently looking for a new job.



Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Joe Williams-2
In reply to this post by Björn Gustavsson-3
> > >5) A *tiny* implementation (written 99% in Erlang and 1% in ANSI standard
> > C)
> >
> > How tiny do you want to go?
> >
>
> I don't see the point with having a tiny implementation.

  I like tiny implementations  - having a tiny implementation increases
the    chances   that    individuals    can   completely    understand
*everything*. It make things easy to port and embed

> Most important for our customers are stability and speed. If that makes
> the implementation more complex (and it does), that's OK.

  I agree here is a speed x complexity trade off:

  How do we choose been

        simple  and slow
        complex and fast

  I choose the simplest solution which is fast enough.

  Currently  we do  research projects  to improve  performance  at the
expense of simplicity - but  not research into improving simplicity at
the expense of performance.

  Why no research  into "slow and simple?" -  IMHO such research would
lead to Erlang's that are  easily portable into hand-held computers and
embedded devices etc.

  It must be small and beautiful  because I might have to change it in
the future. Beauty  is not in the eye  of the beholder - it  is in the
eye of the maintainer :-)

  At home  my 400 MHz celerion is  way fast enough for  all the Erlang
code I have ever written - I  have now bought a 2.4 GHz machine - This
means I should be able to  "pessimise" the Erlang system by a factor 6
and still get the same performance.

  Suppose  this 6  times increase  in performance  mean that  we could
write software that was 6 times shorter ... now that would be nice.

>
> However, we don't want NEEDLESS complexity. Some things are still too
> complicated, and we are working on reducing needless complexity and removing
> options that are not used. Unfortunately, having to be backwards compatible
> prevents us from making all changes we want.
>

  Why  the  backwards  compatibility?  -  *everybody*  (except  project
managers) hates it.

  The only argument I've heard that  bites is "we don't want to re-test
everything" - this argument is correct.

  It  seems like  you have  to combat  "fear of  change"  with "better
testing" - if you could  really test *everything* quickly - then surly
the fear of changes would go away.

  Why do do what everybody else does - put new features that everybody
wants into the "non backwards compatible version" and charge a hell of
a lot to introduce these features into the "old version"

  Cheers

  /Joe


> > If nothing else, I'd like to see most of the BEAM opcode combination
> > stuff in beam_load.c be rolled into the compiler.  This would be a
> > big win in terms of reducing complexity.
>
> I doubt that.
>
> The Beam loader is certainly complex, but it is complexity isolated in
> a single place.
>
> Having the loader there keeps the compiler simpler, and allows us to keep
> the beam file format compatible. Essentially, the format is the same from
> R5B up to R10B and beyond. (In practice, a few minor details prevent you from
> loading and running most R5B modules in R9B and higher, but you can always run
> code compiled several releases back.)
>
> /Bjorn
>






Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Matthias Lang-2
Joe Armstrong writes:

 > Why  the  backwards  compatibility?  -  *everybody*  (except  project
 > managers) hates it.

Codswallop.

 > The only argument I've heard that  bites is "we don't want to re-test
 > everything" - this argument is correct.

 > It  seems like  you have  to combat  "fear of  change"  with "better
 > testing" - if you could  really test *everything* quickly - then surly
 > the fear of changes would go away.

If you had a magic wand which you could wave over a system and have
*everything* tested *quickly*, then you'd forever change the face of
software development.

Where's the wand hidden?

Matthias


Reply | Threaded
Open this post in threaded view
|

So now all I'd like in Erlang is...

Samuel Elliott
On 23/02, Matthias Lang wrote:

| If you had a magic wand which you could wave over a system and have
| *everything* tested *quickly*, then you'd forever change the face of
| software development.
|
| Where's the wand hidden?

Forth?



12