From ok@REDACTED Mon Sep 1 04:28:58 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Mon, 1 Sep 2003 14:28:58 +1200 (NZST) Subject: Tail/Non tail recursion Message-ID: <200309010228.h812SwSD280919@atlas.otago.ac.nz> "Peter Lund" wrote: > Yes, this is what I meant even if I failed to write that into plain > language. I have a faint memory from several years ago, that there > was a compiler optimization for exactly this type of non-recursive > calls, that in fact made it behave like a tail-recursive function. > Maybe someone that KNOWS can tell us if anything like this exist. To so that we're all signing off the same song-sheet, the question is whether the function f([H|T]) -> [X+1 | f(X)]; f([]) -> []. can be tail recursive. The answer of course is that it could be, quite easily. The Prolog equivalent f([H1|T1], [H2|T2]) :- H2 is H1 + 1, f(T1, T2). f([], []). is certainly tail recursive. A couple of years ago I proposed to Kostas Sagonis that HiPE should also do this, but given the need for HiPE to work with BEAM, I don't know if that was ever found to be practical. Basically, you have to pass an additional argument to every function, the address where the result should be stored. This ties up a register that you might have something better to do with, especially on an x86. From thomasl_erlang@REDACTED Mon Sep 1 08:21:34 2003 From: thomasl_erlang@REDACTED (Thomas Lindgren) Date: Sun, 31 Aug 2003 23:21:34 -0700 (PDT) Subject: Tail/Non tail recursion In-Reply-To: <200309010228.h812SwSD280919@atlas.otago.ac.nz> Message-ID: <20030901062134.81535.qmail@web41903.mail.yahoo.com> --- "Richard A. O'Keefe" wrote: > To so that we're all signing off the same > song-sheet, > the question is whether the function > > f([H|T]) -> [X+1 | f(X)]; > f([]) -> []. > > can be tail recursive. > > The answer of course is that it could be, quite > easily. > The Prolog equivalent > > f([H1|T1], [H2|T2]) :- > H2 is H1 + 1, > f(T1, T2). > f([], []). > > is certainly tail recursive. A couple of years ago > I proposed to Kostas > Sagonis that HiPE should also do this, but given the > need for HiPE to work > with BEAM, I don't know if that was ever found to be > practical. First, let me say that I don't support user-accessible destructive operations in Erlang. Keep the language as pure as possible. Under the hood, however, destructive updates are interesting. I know that on smaller programs, it can be a big win. A (very much) older version of Hipe had a destructive assignment BIF, for that purpose and others, e.g., pure, fast hashtables, again a la Prolog. We hand-coded the assignments for some microexamples, and found that it gave good speedups. I don't have the precise numbers anymore. (This was in 96-98.) BEAM for a time had some support for destructive update but I believe this intreacted badly with GC when generational garbage collection appeared, and was removed. This can likely be fixed if there is need for it. (Getting destructive assignment near the speed of C is still difficult, mostly due to garbage collector issues.) The obvious next step would be to automatically detect when to do this, and to introduce assignments and extra "pointer arguments". That would mean one could evaluate the effect on real code. My guess is it could be worthwhile. Best, Thomas __________________________________ Do you Yahoo!? The New Yahoo! Search - Faster. Easier. Bingo. http://search.yahoo.com From vances@REDACTED Mon Sep 1 11:45:15 2003 From: vances@REDACTED (Vance Shipley) Date: Mon, 1 Sep 2003 05:45:15 -0400 Subject: default values in records Message-ID: <20030901094515.GK54422@frogman.motivity.ca> Now we can set all values in a record at once: "There is a new feature introduced in Erlang 5.1/OTP R8B, with which you can set a value to all fields in a record, overriding the defaults in the record specification. The special field _, means "all fields not explicitly specified". > #person{name = "Jakob", _ = '_'}. {person, "Jakob", '_', '_'} But you can't specify them that way: -record(person, {"John","Jakob","Jingleheimer","Schmidt",_=silly}). Too bad too because I've got some nested records where I need all the fields defaulted to zero. Because they're nested it's cumbersome to have to do the _=Value at each level especially when you don't need to go down to that level for any other fields. I can of course set them each to zero in the specification, it would just be so much prettier with the above syntax. -Vance From sean.hinde@REDACTED Mon Sep 1 11:58:46 2003 From: sean.hinde@REDACTED (Sean Hinde) Date: Mon, 1 Sep 2003 10:58:46 +0100 Subject: Parameterised modules Message-ID: Hi, A few thoughts on the proposal for parameterised modules as presented at the Erlang Workshop on Friday. The two main examples given are nice enough in themselves, but comparison with real world apps points out a couple of problems. The first example is of a generic server, where the server module can be parameterised with the name of the callback module and a process registered name: Server = server:new(Name, Mod). If we look at gen_server however there are two startup functions - one with 3 parameters and one with 4 - one which provides a registered name and one which doesn't. It is not clear to me that a parameterised gen_server could offer both variants (given a fixed number of parameters in the module definition), withought imposing on the user some convention that if the registered name was say '$undefined' then the register step would be explicitly skipped. The second example is of providing a user defined log function at module instantiation. Every time I have wanted to provide for a user definable log function I have also wanted to have a built in default logger, and provide the caller the option to provide their own if desired. I do not see any way to provide a default value for a parameter in the proposal for parameterised modules. So in summary the two weaknesses I see are: 1. There is no way to provide variable numbers of instantiation parameters. 2. There is no way to provide default values for instantiation parameters. I do not see an easy way to fix these problems, and I would say that it is fairly serious that these two potentially very common examples are not covered well by the proposal. I am also quite a bit concerned about the increased potential for making spaghetti code - even the likelihood of a server module being defined separately from where it is started up will make code maintenance more costly. Thoughts anyone? Any good examples of where this would be amazing? And apologies if I have confused the heck out of the 90% of folks on the list who were not there on Friday.. Sean From Bengt.Kleberg@REDACTED Mon Sep 1 13:01:40 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Mon, 01 Sep 2003 13:01:40 +0200 Subject: Parameterised modules In-Reply-To: References: Message-ID: <3F532714.4080109@ericsson.com> Sean Hinde wrote: > Hi, > > A few thoughts on the proposal for parameterised modules as presented at > the Erlang Workshop on Friday. > > The two main examples given are nice enough in themselves, but > comparison with real world apps points out a couple of problems. > ...deleted > Thoughts anyone? Any good examples of where this would be amazing? And > apologies if I have confused the heck out of the 90% of folks on the > list who were not there on Friday.. having been there (and still feeling confused :-) i wondered if all the problems solved by parameterised modules would not be solved if fun's could be ''hot code updated''? the question then beeing which would be the most difficult to implement, provide the least spagethi, etc. bengt From bjorn@REDACTED Mon Sep 1 13:41:47 2003 From: bjorn@REDACTED (Bjorn Gustavsson) Date: 01 Sep 2003 13:41:47 +0200 Subject: Tail/Non tail recursion In-Reply-To: <20030901062134.81535.qmail@web41903.mail.yahoo.com> References: <20030901062134.81535.qmail@web41903.mail.yahoo.com> Message-ID: Thomas Lindgren writes: [...] > > BEAM for a time had some support for destructive > update but I believe this intreacted badly with GC > when generational garbage collection appeared, and was > removed. This can likely be fixed if there is need for > it. > There is an instruction in Beam that does a destructive setelement. The instruction is only safe to use immediately after a call to the setelement/3 BIF (i.e. it must be called before the next garbage collection). The instruction is used in when updating a record with more than one new field, such as: Rec#rec{a=A,b=B} /Bjorn -- Bj?rn Gustavsson Ericsson Utvecklings AB bjorn@REDACTED ?T2/UAB/F/P BOX 1505 +46 8 727 56 87 125 25 ?lvsj? From sean.hinde@REDACTED Mon Sep 1 14:18:01 2003 From: sean.hinde@REDACTED (Sean Hinde) Date: Mon, 1 Sep 2003 13:18:01 +0100 Subject: No subject Message-ID: <549B16D0-DC76-11D7-B9A9-000A95927CCE@mac.com> Hi, There was in interesting interchange between Mike Williams and Joe Armstrong at the Erlang workshop on Friday about whether it was a mistake to make link/1 bidirectional or not. The conclusion was that both monitor and link were needed and that both are now provided with the addition of the monitor/2 bif. Maybe it is time to finish the job and add the atomic spawn_monitor/3 bif, which would prevent spawned processes killing the spawner (by sending {'DOWN' etc instead of {'EXIT' etc) The number of times I have made a process trap exits and then keep an ets table of all known spawned worker processes just so that I can respond correctly to 'EXIT' messages from elsewhere is getting quite large, and a spawn_monitor bif would solve this very elegantly, apart from the other advantages. R10 maybe? Sean From ulf.wiger@REDACTED Mon Sep 1 14:40:01 2003 From: ulf.wiger@REDACTED (=?ISO-8859-1?Q?Ulf_Wiger_=28=C4L2/EAB=29?=) Date: Mon, 1 Sep 2003 14:40:01 +0200 Subject: (spawn_monitor/3) Message-ID: <76E5F712842F5F49A35738622BAA0F4F9EA6E4@ESEALNT442.al.sw.ericsson.se> I think one reason why this BIF hasn't been added is that you will get a DOWN message anyway, since calling erlang:monitor/2 on a non-existing process will do just that. What do you gain, apart from one line of code, by making it atomic? Granted, in the distributed case, you save some network traffic. /Uffe -----Original Message----- From: Sean Hinde [mailto:sean.hinde@REDACTED] Sent: Monday, September 01, 2003 14:18 To: Erlang Questions Subject: Hi, There was in interesting interchange between Mike Williams and Joe Armstrong at the Erlang workshop on Friday about whether it was a mistake to make link/1 bidirectional or not. The conclusion was that both monitor and link were needed and that both are now provided with the addition of the monitor/2 bif. Maybe it is time to finish the job and add the atomic spawn_monitor/3 bif, which would prevent spawned processes killing the spawner (by sending {'DOWN' etc instead of {'EXIT' etc) The number of times I have made a process trap exits and then keep an ets table of all known spawned worker processes just so that I can respond correctly to 'EXIT' messages from elsewhere is getting quite large, and a spawn_monitor bif would solve this very elegantly, apart from the other advantages. R10 maybe? Sean From svenolof@REDACTED Mon Sep 1 13:19:46 2003 From: svenolof@REDACTED (Sven-Olof Nystr|m) Date: Mon, 1 Sep 2003 13:19:46 +0200 Subject: A soft-typing system for Erlang Message-ID: <16211.11090.530085.519920@gargle.gargle.HOWL> The system I presented at the Erlang workshop can be downloaded at Sven-Olof -- Sven-Olof Nystrom Comp Sci Dept, Uppsala University, Box 337, S-751 05 Uppsala SWEDEN svenolof@REDACTED, http://www.csd.uu.se/~svenolof phone: +46 18 471 76 91, fax: +46 18 51 19 25 From earlyriser@REDACTED Mon Sep 1 14:16:17 2003 From: earlyriser@REDACTED (Sean Hinde) Date: Mon, 1 Sep 2003 13:16:17 +0100 Subject: spawn_monitor/3 Message-ID: <169BD65C-DC76-11D7-BC80-000A95927CCE@mac.com> Hi, There was in interesting interchange between Mike Williams and Joe Armstrong at the Erlang workshop on Friday about whether it was a mistake to make link/1 bidirectional or not. The conclusion was that both monitor and link were needed and that both are now provided with the addition of the monitor/2 bif. Maybe it is time to finish the job and add the atomic spawn_monitor/3 bif, which would prevent spawned processes killing the spawner (by sending {'DOWN' etc instead of {'EXIT' etc) The number of times I have made a process trap exits and then keep an ets table of all known spawned worker processes just so that I can respond correctly to 'EXIT' messages from elsewhere is getting quite large, and a spawn_monitor bif would solve this very elegantly, apart from the other advantages. R10 maybe? Sean From sean.hinde@REDACTED Mon Sep 1 14:53:36 2003 From: sean.hinde@REDACTED (Sean Hinde) Date: Mon, 1 Sep 2003 13:53:36 +0100 Subject: (spawn_monitor/3) In-Reply-To: <76E5F712842F5F49A35738622BAA0F4F9EA6E4@ESEALNT442.al.sw.ericsson.se> Message-ID: <4D2D8CF0-DC7B-11D7-B9A9-000A95927CCE@mac.com> On Monday, September 1, 2003, at 01:40 pm, Ulf Wiger (?L2/EAB) wrote: > > I think one reason why this BIF hasn't been added is that > you will get a DOWN message anyway, since calling > erlang:monitor/2 on a non-existing process will do just that. OK, I didn't cotton on to that twist. > > What do you gain, apart from one line of code, by making > it atomic? Granted, in the distributed case, you save some > network traffic. Well, you gain consistency with the spawn link case. It feels wrong to have the two mechanisms for monitoring other processes have such different meanings and operation. Apart from anything else it would probably never have occurred to me (having been brought up on the religion that spawn should never be used and that spawn_link is the only way to make link atomic) that Pid = spawn(Fun), monitor(process, Pid) is correct, and the only way to achieve the aim, but Pid = spawn(Fun), link(Pid) is utterly verboten. Sean From mikpe@REDACTED Mon Sep 1 15:46:58 2003 From: mikpe@REDACTED (Mikael Pettersson) Date: Mon, 1 Sep 2003 15:46:58 +0200 Subject: Parameterised modules In-Reply-To: References: Message-ID: <16211.19922.818355.785968@gargle.gargle.HOWL> Sean Hinde writes: > Hi, > > A few thoughts on the proposal for parameterised modules as presented > at the Erlang Workshop on Friday. > > The two main examples given are nice enough in themselves, but > comparison with real world apps points out a couple of problems. > > The first example is of a generic server, where the server module can > be parameterised with the name of the callback module and a process > registered name: > > Server = server:new(Name, Mod). > > If we look at gen_server however there are two startup functions - one > with 3 parameters and one with 4 - one which provides a registered name > and one which doesn't. It is not clear to me that a parameterised > gen_server could offer both variants (given a fixed number of > parameters in the module definition), withought imposing on the user > some convention that if the registered name was say '$undefined' then > the register step would be explicitly skipped. Either using a convention with an out-of-band value denoting "don't" or adding a second boolean DoReg parameter will work. (But see below.) > The second example is of providing a user defined log function at > module instantiation. Every time I have wanted to provide for a user > definable log function I have also wanted to have a built in default > logger, and provide the caller the option to provide their own if > desired. I do not see any way to provide a default value for a > parameter in the proposal for parameterised modules. 1. Whoever does the instantiation gets to choose. This works perfectly in Standard ML, whose parametrized module system was the original inspiration for HiPE's work on the same. 2. Something like -module(foo, [{Label,Default},...]) and change foo:new() calls to pass the values by Label foo:new([{'Log', sean_logger}]) and any omitted Label would get its default value. This would be a fairly simple change I think. This could also solve your maybe-register problem. Omitting the RegisteredName parameter lets it take on a default value, whose encoding is private to the module. Clean, no? /Mikael From sean.hinde@REDACTED Mon Sep 1 16:28:25 2003 From: sean.hinde@REDACTED (Sean Hinde) Date: Mon, 1 Sep 2003 15:28:25 +0100 Subject: Parameterised modules In-Reply-To: <16211.19922.818355.785968@gargle.gargle.HOWL> Message-ID: <8BDE857A-DC88-11D7-B9A9-000A95927CCE@mac.com> On Monday, September 1, 2003, at 02:46 pm, Mikael Pettersson wrote: > Sean Hinde writes: >> Hi, >> >> some convention that if the registered name was say '$undefined' then >> the register step would be explicitly skipped. > > Either using a convention with an out-of-band value denoting "don't" > or adding a second boolean DoReg parameter will work. (But see below.) But then we are getting pretty ugly, with new case specific code required in the guts of the module of similar complexity of that which we hope to remove. > >> The second example is of providing a user defined log function at >> module instantiation. Every time I have wanted to provide for a user >> definable log function I have also wanted to have a built in default >> logger, and provide the caller the option to provide their own if >> desired. I do not see any way to provide a default value for a >> parameter in the proposal for parameterised modules. > > 1. Whoever does the instantiation gets to choose. This works > perfectly in Standard ML, whose parametrized module system > was the original inspiration for HiPE's work on the same. > > 2. Something like > > -module(foo, [{Label,Default},...]) > > and change foo:new() calls to pass the values by Label > > foo:new([{'Log', sean_logger}]) > > and any omitted Label would get its default value. So you are proposing that new() should always have a single parameter which is a list of tagged tuples with magic properties? This would work I think, though it is getting away from the reason to provide the feature (Clearer code). If this was taken further so that a call to foo:new() was a wrapper for foo:new([]) this would be quite clean. Maybe even then using a parameterised module without ever calling new() would give the default behaviour - thus removing the burden of additional understanding required before a module could be used at all. This is not as pretty as Richards version though.. > > This would be a fairly simple change I think. > > This could also solve your maybe-register problem. Omitting the > RegisteredName parameter lets it take on a default value, whose > encoding is private to the module. Clean, no? I'm still not really convinced that the benefit in normal everyday code is enough to justify the additional cost of maintenance of systems which use this feature - I envision many hours of searching for the place where some magic imperative style variable got it's value when reading someone elses code, especially when it is probably nowhere to be seen in the backtrace of some crashdump from a live system. Hmmmm Sean From mikpe@REDACTED Mon Sep 1 16:45:02 2003 From: mikpe@REDACTED (Mikael Pettersson) Date: Mon, 1 Sep 2003 16:45:02 +0200 Subject: Parameterised modules In-Reply-To: <8BDE857A-DC88-11D7-B9A9-000A95927CCE@mac.com> References: <16211.19922.818355.785968@gargle.gargle.HOWL> <8BDE857A-DC88-11D7-B9A9-000A95927CCE@mac.com> Message-ID: <16211.23406.303742.965502@gargle.gargle.HOWL> Sean Hinde writes: > So you are proposing that new() should always have a single parameter > which is a list of tagged tuples with magic properties? This would work > I think, though it is getting away from the reason to provide the > feature (Clearer code). > > If this was taken further so that a call to foo:new() was a wrapper for > foo:new([]) this would be quite clean. Maybe even then using a > parameterised module without ever calling new() would give the default > behaviour - thus removing the burden of additional understanding > required before a module could be used at all. This is not as pretty as > Richards version though.. All I'm proposing is to change from call-with-parameters-by-postion to call-with-parameters-by-label. The first is commonplace but can't handle default values for omitted parameters. The second is bulkier to type (but not much) but handles omitted parameters easily; it also has some precedence in record syntax and other languages like SML (in SML, tuples are syntactic sugar for records with numeric labels). The callback example isn't the one that motivates me. I'm a diehard SML fan, and I love the way SML lets me structure code and create multiple specialised instances of generic modules. (I personally don't care for default parameters to modules. I only proposed it because you seemed to want a way to either supply a given parameter or not -- with the module taking appropriate action.) /Mikael From sean.hinde@REDACTED Mon Sep 1 16:55:37 2003 From: sean.hinde@REDACTED (Sean Hinde) Date: Mon, 1 Sep 2003 15:55:37 +0100 Subject: Parameterised modules In-Reply-To: <16211.23406.303742.965502@gargle.gargle.HOWL> Message-ID: <59010D98-DC8C-11D7-B9A9-000A95927CCE@mac.com> On Monday, September 1, 2003, at 03:45 pm, Mikael Pettersson wrote: > The callback example isn't the one that motivates me. I'm a diehard > SML fan, and I love the way SML lets me structure code and create > multiple specialised instances of generic modules. I guess this is what I was really asking - the examples given so far do not provide (to me at least) a very convincing case for adding this feature to the language. Is there something else about SML which makes it well suited to this sort of programming? Perhaps you could provide a nice example where parameterised modules allowed you to do something very elegantly where it would have been difficult without? > > (I personally don't care for default parameters to modules. I only > proposed it because you seemed to want a way to either supply a > given parameter or not -- with the module taking appropriate action.) I don't have any particular preference either (yet!), this was driven from thinking about Richard's logger callback example and cases where I might want to use this pattern. > > /Mikael From bjarne@REDACTED Mon Sep 1 19:38:34 2003 From: bjarne@REDACTED (=?iso-8859-1?Q?Bjarne_D=E4cker?=) Date: Mon, 01 Sep 2003 19:38:34 +0200 Subject: 2nd ACM SIGPLAN Erlang Workshop Message-ID: <003401c370af$e5005da0$e00969d4@segeltorp> Papers and photographs from the workshop can be found at http://www.erlang.se/workshop/2003/ There were 47 registered participants. Bjarne -------------- next part -------------- An HTML attachment was scrubbed... URL: From jilani.khaldi@REDACTED Mon Sep 1 23:24:21 2003 From: jilani.khaldi@REDACTED (Jilani Khaldi) Date: Mon, 01 Sep 2003 23:24:21 +0200 Subject: Alter Mnesia Table Message-ID: Hi, I have craeted a Mnesia database with a single table: -record(persons, {code, f_name, l_name, address, home_page}). and I have put in some records. Now, I want to add the field "e_mail ", in position 3 (just after l_name) and change "f_name" with "first_name" and delete the field "home_page". I use alter table to make all these changes with an SQL RDBMD, but how to do it with Mnesia? An other question: does Mnesia support referential integrity? Thanks! jilani -- http://www.jilani.net From sean.hinde@REDACTED Tue Sep 2 00:09:07 2003 From: sean.hinde@REDACTED (Sean Hinde) Date: Mon, 1 Sep 2003 23:09:07 +0100 Subject: Alter Mnesia Table In-Reply-To: Message-ID: On Monday, September 1, 2003, at 10:24 pm, Jilani Khaldi wrote: > Hi, > > I have craeted a Mnesia database with a single table: > > -record(persons, {code, f_name, l_name, address, home_page}). > > and I have put in some records. > Now, I want to add the field "e_mail ", in position 3 (just after > l_name) and change "f_name" with "first_name" and delete the field > "home_page". > I use alter table to make all these changes with an SQL RDBMD, but how > to do it with Mnesia? Read up about mnesia:transform_table - all will be revealed. If your table is so large that this proves impossible within the memory constraints of your machine or the emulator, you can also take a backup and transform the backup using mnesia:traverse_backup > > An other question: does Mnesia support referential integrity? Only by allowing access in a controlled manner using your own carefully crafted transactions. There is no built in way to enforce relationships between different tables (I assume this is the sort of thing you meant). Sean From anders_nygren2002@REDACTED Tue Sep 2 01:06:22 2003 From: anders_nygren2002@REDACTED (=?iso-8859-1?q?Anders=20Nygren?=) Date: Tue, 2 Sep 2003 01:06:22 +0200 (CEST) Subject: 2nd ACM SIGPLAN Erlang Workshop In-Reply-To: <003401c370af$e5005da0$e00969d4@segeltorp> Message-ID: <20030901230622.52439.qmail@web14607.mail.yahoo.com> --- Bjarne_D?cker skrev: > Papers and photographs from the > workshop can be found at > > http://www.erlang.se/workshop/2003/ > > There were 47 registered participants. > > Bjarne > HI Maybe I am blind or to earl, but I can not find the papers. Are they really avalable somewhere? /Anders Yahoo! Mail - Gratis: 6 MB lagringsutrymme, spamfilter och virusscan. Se mer p? http://se.mail.yahoo.com From ok@REDACTED Tue Sep 2 01:06:10 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Tue, 2 Sep 2003 11:06:10 +1200 (NZST) Subject: Tail/Non tail recursion Message-ID: <200309012306.h81N6AqE229387@atlas.otago.ac.nz> I mentioned how f([H|T]) -> [X+1 | f(X)]; f([]) -> []. could be tail recursive. Thomas Lindgren wrote: First, let me say that I don't support user-accessible destructive operations in Erlang. Keep the language as pure as possible. Under the hood, however, destructive updates are interesting. I am rather baffled by this, in context. The scheme I alluded to doesn't use destructive operations, only initialising writes. (While a data structure might be constructed incrementally, it would only become readable once it was fully initialised.) It does admittedly destroy the "all pointers point downwards" property Erlang might otherwise have enjoyed, but that is another matter. The obvious next step would be to automatically detect when to do this, and to introduce assignments and extra "pointer arguments". That would mean one could evaluate the effect on real code. For destructive update generally, many people have worked on the problem of automatically detecting when it can safely be used. In many ways the simplest answer is that found in the Clean and Mercury "type" systems. It's not clear to me whether such methods can easily be adapted to Erlang's dynamic module system. (Module replacement is very much a "user-accessible destructve operation", by the way.) From kurtw@REDACTED Tue Sep 2 04:50:38 2003 From: kurtw@REDACTED (Kurt at DBC) Date: Tue, 02 Sep 2003 14:50:38 +1200 Subject: Maybe Erlang is OO after all? In-Reply-To: <3F49D53D.3050105@web.de> References: <3F49834E.6060402@dbc.co.nz> <3F49D53D.3050105@web.de> Message-ID: <3F54057E.6040903@dbc.co.nz> Joachim Durchholz wrote: > Kurt at DBC wrote: > > I think this is more a problem of the way that OO is typically implemented. and > It's also a problem of the way that OO classes are typically written. Which I whole-heartedly agree with. But I'd also suggest that how a paradigm is typically implemented and how it is typically used provide the most useful description of that paradigm. > With that design, again there's a lot of state involved. If a language > makes it easy to package out-of-band data such as error diagnostics into > results, and where it's likewise easy to disassemble that data on the > caller side, then it's not necessary to have this. Unsure of 'out-of-band', but the (typically implemented) OO method of communication via procedure call is what I was driving at: the sequence of communicating is explicit (discrete) as opposed to Erlangs 'handle any message at any time' approach (continuous). > I think these difference contribute more to the difficulties in OO > design than any difference between time modelling. Actually, I don't I don't know how much Java has changed over the last few years (and am very conscious that there are some knowledgeable Java people on the list), but not that long ago one of the most widely promoted communication methods was to declare a local proxy object and implement comms as if they were local procedure calls. Presumably, when that worked, it would work very well, but when it didn't you'd be in a world of hurt. Regardless, at the time it was widely held as the OO way of doing communication. But once you're doing that, you are explicitly managing the sequence of communication, and it seems to me that this lower level of managing the sequence *is* the difficulty when compared to my idealised view of Erlangs approach of check what messages, if any, have arrived and handle them. I don't know that I've done a much better job of explaining myself this time ;) - I feel like I'm trying to describe what a grey blanket in the fog would look like if it wasn't there * Also Richard A. O'Keefe wrote: > (It's good to see other people in NZ interested > in Erlang, though.) And it is ;) Perhaps one of us could host the NZ Erlounge, we wouldn't even need a lounge, we could have the ErlDoorway, or the ErlBroomCupboard. * describing black cats that aren't in dark rooms is *way* beyond me. Cheers, Kurt. From thomasl_erlang@REDACTED Tue Sep 2 08:10:19 2003 From: thomasl_erlang@REDACTED (Thomas Lindgren) Date: Mon, 1 Sep 2003 23:10:19 -0700 (PDT) Subject: Tail/Non tail recursion In-Reply-To: <200309012306.h81N6AqE229387@atlas.otago.ac.nz> Message-ID: <20030902061019.17194.qmail@web41902.mail.yahoo.com> --- "Richard A. O'Keefe" wrote: > I mentioned how > f([H|T]) -> [X+1 | f(X)]; > f([]) -> []. > could be tail recursive. > > Thomas Lindgren wrote: > > First, let me say that I don't support > user-accessible > destructive operations in Erlang. Keep the language > as > pure as possible. Under the hood, however, > destructive > updates are interesting. > > I am rather baffled by this, in context. > The scheme I alluded to doesn't use destructive > operations, > only initialising writes. (While a data structure > might be > constructed incrementally, it would only become > readable once > it was fully initialised.) Let me explain my terminological choice. For our purposes, the example loop is a two step process: 1. create A = [X+1 | ] 2. in the next iteration of the loop, update the tail element of A. The is written only so that the GC can scan the data structure. If the GC can detect this anyway, then one can omit that write. Between 1 and 2, there may in general be a garbage collection. Thus, if a generational collector is used, the code needs to check whether A was tenured or not, and if tenured, record an old-to-new pointer. (As I recall, BEAM:s GC furthermore did not support such recording, since there was no need for it elsewhere. I'm not sure of how things are now.) The general operation is then, in my mind at least, a full destructive update, hence the term. Certainly, one can detect special cases and optimize the runtime system, change the GC, etc. to reduce costs. Taking advantage of the writes being initialising is one such case. > [compile time reuse and module replacement as destructive operations] No, I was thinking of the much simpler and more restricted case being discussed, and using destructive updates of terms to implement this technique. Sorry about being imprecise. Disregarding terminology, while this technique seems fairly straightforward, I for one haven't seen it used in functional language implementations. (Well, possibly excepting Jim Larus's thesis, which is a corner case.) I think it would be interesting to try it out. Best, Thomas __________________________________ Do you Yahoo!? The New Yahoo! Search - Faster. Easier. Bingo. http://search.yahoo.com From bjarne@REDACTED Tue Sep 2 09:23:00 2003 From: bjarne@REDACTED (=?iso-8859-1?Q?Bjarne_D=E4cker?=) Date: Tue, 02 Sep 2003 09:23:00 +0200 Subject: 2nd ACM SIGPLAN Erlang Workshop References: <20030901230622.52439.qmail@web14607.mail.yahoo.com> Message-ID: <000c01c37123$0ae3c840$f71369d4@segeltorp> Hello >HI >Maybe I am blind or to earl, but I can not find the >papers. >Are they really avalable somewhere? Well, if you look at http://www.erlang.se/workshop/2003/ then you find after each paper (except by the invited speakers) a little parenthesis looking like " (pdf) ". That is the link ! And all shall be revealed ! Bjarne From bjorn@REDACTED Tue Sep 2 10:09:16 2003 From: bjorn@REDACTED (Bjorn Gustavsson) Date: 02 Sep 2003 10:09:16 +0200 Subject: Tail/Non tail recursion In-Reply-To: <20030902061019.17194.qmail@web41902.mail.yahoo.com> References: <20030902061019.17194.qmail@web41902.mail.yahoo.com> Message-ID: Thomas Lindgren writes: [...] > Between 1 and 2, there may in general be a garbage > collection. Thus, if a generational collector is used, > the code needs to check whether A was tenured or not, > and if tenured, record an old-to-new pointer. > > (As I recall, BEAM:s GC furthermore did not support > such recording, since there was no need for it > elsewhere. I'm not sure of how things are now.) The current GC does not support pointers from the old generation to the new. There is a newer, experimental, not stable GC implementation that includes a write barrier to allow pointers from the old generation to the youngest. Regarding making the cons operation tail-recursive, I cannot see that it can be done without entirely re-designing the Beam instruction set in a non-backward compatible way. Therefore, it will probably never be done. /Bjorn -- Bj?rn Gustavsson Ericsson Utvecklings AB bjorn@REDACTED ?T2/UAB/F/P BOX 1505 +46 8 727 56 87 125 25 ?lvsj? From ulf.wiger@REDACTED Tue Sep 2 12:57:42 2003 From: ulf.wiger@REDACTED (=?ISO-8859-15?Q?Ulf_Wiger_=28=C4L2/EAB=29?=) Date: Tue, 2 Sep 2003 12:57:42 +0200 Subject: Alter Mnesia Table Message-ID: <76E5F712842F5F49A35738622BAA0F4F9EA6E8@ESEALNT442.al.sw.ericsson.se> From: Jilani Khaldi [mailto:jilani.khaldi@REDACTED] >An other question: does Mnesia support referential integrity? The user contribution 'rdbms' adds referential integrity support to mnesia, as well as type and domain checks and transaction-safe triggers. http://www.erlang.org/user.html#rdbms-1.3 I have a slightly improved version that has not yet been released. The main addition is that it has slightly better support for incrementally adding referential integrity constraints to already existing tables. /Uffe From joachim.durchholz@REDACTED Tue Sep 2 13:22:34 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Tue, 02 Sep 2003 13:22:34 +0200 Subject: Maybe Erlang is OO after all? In-Reply-To: <3F54057E.6040903@dbc.co.nz> References: <3F49834E.6060402@dbc.co.nz> <3F49D53D.3050105@web.de> <3F54057E.6040903@dbc.co.nz> Message-ID: <3F547D7A.1040908@web.de> Kurt at DBC wrote: > Joachim Durchholz wrote: >> With that design, again there's a lot of state involved. If a language >> makes it easy to package out-of-band data such as error diagnostics >> into results, and where it's likewise easy to disassemble that data on >> the caller side, then it's not necessary to have this. > > Unsure of 'out-of-band', Say, the sqrt function should return the square root of its argument. Or it should return an error indication. The error indication is what's called "out-of-band data": it's not part of the normal "band" that the sqrt function uses to return ordinary results. In a language with easily defined record types, it's simple to make sqrt return either (OK, 2.0) or (Failure, "-4.0 is not a valid argument for sqrt"). In a language with pattern matching on records, the caller can likewise easily write (made-up syntax) case sqrt (x) (OK, res) -> (_, msg) -> > but the (typically implemented) OO method > of communication via procedure call is what I was driving at: > the sequence of communicating is explicit (discrete) as opposed to > Erlangs 'handle any message at any time' approach (continuous). The approach you're aiming at isn't discrete, it's transactional (since messages are discrete anyway): a client "opens" the square root facility, stuffs an argument into it, extracts the results, and closes the facility so that it becomes free for other clients. The problem with this approach is that no language really ensures that these transactions are atomic. For example, a subclass of the square root facility could call itself, inadvertently accessing or even modifying internal state that's not consistent with the intended interface of the class. (I've seen this happen many times; it becomes a real issue once a few dozen classes are involved. Think File classes, and a class that uses them to implement virtual file systems within a file, plus a specialized File class that accesses these virtual files - it's all too easy to get confused without noticing it.) The problem with this transactional style is that there are many, many more ways to have erroneous access to an object (e.g. trying to start another transaction while another transaction is in progress). This problem would persist even if typical OO languages had full nested transaction facilities. Hope I've made myself a bit clearer this time :-) Regards, Jo From thomasl_erlang@REDACTED Tue Sep 2 18:53:37 2003 From: thomasl_erlang@REDACTED (Thomas Lindgren) Date: Tue, 2 Sep 2003 09:53:37 -0700 (PDT) Subject: Fwd: Re: Tail/Non tail recursion Message-ID: <20030902165337.79493.qmail@web41906.mail.yahoo.com> I forgot to CC the list ... Note: forwarded message attached. __________________________________ Do you Yahoo!? The New Yahoo! Search - Faster. Easier. Bingo. http://search.yahoo.com -------------- next part -------------- An embedded message was scrubbed... From: Thomas Lindgren Subject: Re: Tail/Non tail recursion Date: Tue, 2 Sep 2003 09:49:16 -0700 (PDT) Size: 1717 URL: From mikael.karlsson@REDACTED Tue Sep 2 21:02:13 2003 From: mikael.karlsson@REDACTED (Mikael Karlsson) Date: Tue, 2 Sep 2003 21:02:13 +0200 Subject: Enterprise Erlang Beams? In-Reply-To: References: <200308221539.45014.mikael.karlsson@creado.com> <200308242154.57320.mikael.karlsson@creado.com> Message-ID: <200309022102.13087.mikael.karlsson@creado.com> Hi, Wed 27 augusti 2003 10:36 Vlad Dumitrescu wrote: > - I don't think it would be good to try to imitate J2EE. Many J2EE features > are aimed at solving things that are non-problems in Erlang (as you pointed > out also). Maybe a better way to express the goal would be "implementing an > Enterprise Application Server". OK, I guess you would like to have some kind of transaction support still? > - An aspect where Java has the upper hand is security: JVM is acting as a > sandbox, while BeamVM isn't. This might be important. I am not sure I understand why this is important on the server side. What security issues are adressed by the JVM that makes an Erlang implementation too risky? Is it programming mistakes or vulnerability to external attacks? > I have a feeling there was more to say, but I'll be back when I remember. > :-) best regards, Please do :-) Thanks Mikael From ok@REDACTED Wed Sep 3 03:43:28 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Wed, 3 Sep 2003 13:43:28 +1200 (NZST) Subject: Tail/Non tail recursion Message-ID: <200309030143.h831hSBa301675@atlas.otago.ac.nz> Thomas Lindgren wrote: Let me explain my terminological choice. For our purposes, the example loop is a two step process: 1. create A = [X+1 | ] 2. in the next iteration of the loop, update the tail element of A. The is written only so that the GC can scan the data structure. If the GC can detect this anyway, then one can omit that write. Correct: there are plausible, even simple, implementations in which the placeholder is NEVER WRITTEN AT ALL. Which means that the write which _does_ fill it in is not a destructive operation. It seems a little unreasonable to call an operation a "destructive" update just because *some* (and definitely not all) implementations might have put something there first. After all, even for X = [H|T] an implementation *could* do R <- allocate a pair cell and fill it with zeros st T, 0(R) ^^^^^^^^^^^^^^^^^^^^^^ st H, 4(R) add R, , X in which case what data construction _wouldn't_ be a "destructive" operation. Between 1 and 2, there may in general be a garbage collection. Thus, if a generational collector is used, the code needs to check whether A was tenured or not, and if tenured, record an old-to-new pointer. But this is a contigent fact about a garbage collector, *not* an intrinsic fact about the operation itself. The significant fact for the garbage collector is not so much whether the initialisation overwrites defined data or not, but the direction of the link it establishes. I thought it might be interesting to get some actual numbers. Recall that we are discussing f([H|T]) -> [H+1 | f(T)]; f([]) -> []. I implemented this in C, using only the constructions I thought a fairly dumb Erlang-to-C compiler might use. One version used body recursion; the other used tail recursion with a where-to-store- the-address argument. H+1 was implemented by calling an out-of-line function. There was no garbage collector, but the code did check whether a garbage collection was needed. On a SunBlade 100, the tail recursive version was no less than 12 times faster. Of course, the SPARC function calling convention dumps quite a lot of stuff into memory whenever the register windows overflow, so this is perhaps a little unfair, but if I had such a compiler, that's the machine I'd want it for. On an Alpha, which doesn't have register windows, and has a somewhat saner function calling convention, the tail recursive version was only 4 times faster. That's still well worth having. The *big* advantage of using tail recursion when you can, of course, is that you don't need so much space for the stack; if you put the stack and the per-process heap in the same block of memory, you don't get so many garbage collections because the stack doesn't keep running into the heap. This also serves to improve performance. That's all very well, but would such an implementation strategy be _useful_ very often? I decided to take an Erlang file and check. I didn't write it. The author knew about tail recursion optimisation, and may well have avoided tail-recursion-through-a-constructor because he knew that _didn't_ count as tail recursion. There are certainly more calls to reverse/1 than I would have felt comfortable with. The important thing is that the file is not "about" list processing or any other data structure. Functions : 41 Clauses : 87 2.12 clauses per function All returns : 110 2.68 returns per function, 1.26 per clause ..Appends : 3 2.7% of all returns ..Constructors: 4 3.6% of all returns ..Simple : 51 46.4% of all returns ..Tail calls : 41 37.3% of all returns ..Exits : 11 10.0% of all returns Body calls : 57 Exit: the last action is exit(...) Tail: the last action is foo(...) for some function, self or other Simple: the result is a variable, constant, arithmetic expression, &c Constructor: the result contains at least one function call inside a constructor, the last outermost such is picked as "tail" call. Append: the result is ++ a constructor, and can be compiled into fast inline code. If we discount the exit()s as indicating errors, we get simple returns : 51 51.5% plain tail calls: 41 41.4% constructor tail: 7 7.1% total : 99 Roughly one return in 2 is a simple result (constant, variable, &c). Roughly one function call in 2 is a body call. Roughly half of the returns (48%) are roughly half of the function calls (46%) and are (6/7) or could be (1/7) tail calls. These are static frequencies, not dynamic frequencies, and they are only for one file. To be honest, I was expecting the static frequency of C and A calls to be lower, and was pleasantly surprised. From vlad_dumitrescu@REDACTED Wed Sep 3 08:56:47 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Wed, 3 Sep 2003 08:56:47 +0200 Subject: Enterprise Erlang Beams? References: <200308221539.45014.mikael.karlsson@creado.com> <200308242154.57320.mikael.karlsson@creado.com> <200309022102.13087.mikael.karlsson@creado.com> Message-ID: Hello, First, let me remind you that I am no J2EE "power user" either. So I may be dead wrong, but this is what I think and I welcome criticism. ----- Original Message ----- From: "Mikael Karlsson" > Wed 27 augusti 2003 10:36 Vlad Dumitrescu wrote: > > - I don't think it would be good to try to imitate J2EE. > > OK, I guess you would like to have some kind of transaction support still? Yes, of course. What I meant was that I think it is the application server's functionality that has to be replicated, not necessarily by using anything similar to Java beans. Maybe you didn't mean that either, but it wasn't clear (the name Erlang Beams is a pun against such an analogy) and I think it is important to point it out. > > - An aspect where Java has the upper hand is security: JVM is acting as a > > sandbox, while BeamVM isn't. This might be important. > > I am not sure I understand why this is important on the server side. What > security issues are adressed by the JVM that makes an Erlang implementation > too risky? Is it programming mistakes or vulnerability to external attacks? Both. That it is so simple in a distributed environment such as Erlang to run on another node something like os:cmd("rm -rf /") is giving me shivers. If malevolent code sneaks into the system, then everything is wide open. Programming errors might not be as destructive, but they can happen. An EJB can't do some things that a regular bean can: - no threading - no graphics - can't be a network server (**) - can't write to static fields (*) - no IO (**) - can't load native libraries (***) - can't use 'this' as argument ore return value (**) - no loopback calls (i.e. EJB are non-reentrant) (*) I marked with stars according to how much I think each of those are related to security issues. Except for the last one (I think), Java EE and the app server enforce these limitations. Something similar should be present in any other implementation of an app server. Of course, it's possible to equate EJB = Erlang process, and set the responsibility of not doing anything "bad" to the programmers, but I wouldn't want to use such an app server in a production environment. Not even if it was me who wrote all code. I think too that an Erlang app server could be a very good product, but there are still issues to be solved. Hopefully this discussion will lead to some advances. I'm glad you started it. regards, /Vlad From rvg@REDACTED Wed Sep 3 13:43:05 2003 From: rvg@REDACTED (Rudolph van Graan) Date: Wed, 3 Sep 2003 13:43:05 +0200 Subject: Inets/http Message-ID: <1F42BB97D787C048BCC519FF28048AC367FB@galileo.ifoni.com> Hi all, Today I have a question regarding the support of the http module in inets. I've recently had to write an application that uses http to retrieve some information. I found some issues with the way the code deals with a) Microsoft IIS redirects [a known issue] and b) handling of spaces in GET parameters. I've mailed the author of http requestion help building a patch to address these issues, but to date I had no response. So, how does one report bugs on http and how can I submit possible fixes? I couldn't find any reference in the code to standard unit tests, so I don't know if my patch broke anything. Does someone know of tests written for http? Issue 1: The first issue has to do with the comments at the top of the http.erl module: %% Note: %% - Some servers (e.g. Microsoft-IIS/5.0) may sometimes not return a proper %% 'Location' header on a redirect. %% The client will fail with {error,no_scheme} in these cases. Suppose the url one is trying to fetch is "http://some.server.com/blah.asp" and it tries to redirect to "blie.asp" on the same server, the Location header field contains "blie.asp" instead of "http://some.server.asp/blie.asp". Is this correct? I've found that when an IIS 5.0 server redirects, it does not expand the URL back to its complete form. I *have* to get http.erl to work properly with someone else's website, so I've started at trying to fix this problem [by letting httpc_handler.erl] fix the Location when it is in this state. I've built a simple fix, but I cannot regression test it using the unittests for the module, nor do I know how to include this in the actual erlang distribution. Issue 2: The other problem has to do with a URL that looks like this "http://some.server.com/blah.asp?data=Some%20Text" The %20 means a space in the data. Now, http "prepares" the url and then change the %20 into a space, so the actual URL requested from the Web server is "http://some.server.com/blah.asp?data=Some Text" which clearly is not properly formed. I feel that the code should in fact change any embedded spaces into the hex version, but not change embedded hex characters back to the actual form. Any suggestions? Thank you for all the help in the past. Rgds, Rudolph From richardc@REDACTED Wed Sep 3 14:34:49 2003 From: richardc@REDACTED (Richard Carlsson) Date: Wed, 3 Sep 2003 14:34:49 +0200 (MET DST) Subject: Packages in Erlang: new documentation In-Reply-To: <200309030143.h831hSBa301675@atlas.otago.ac.nz> References: <200309030143.h831hSBa301675@atlas.otago.ac.nz> Message-ID: Since the R9B release of Erlang, "packages" (hierarchical module namespaces) have been available for testing by the Erlang community. It seems that the information about this, and how it works, has not reached enough people. I have therefore written a new piece of documentation about packages in Erlang, in the hope that it will be better understood, and more people will try it out: http://www.csd.uu.se/projects/hipe/packages.html In particular, see the section about migrating code into packages. All comments appreciated, /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ From luke@REDACTED Wed Sep 3 15:41:02 2003 From: luke@REDACTED (Luke Gorrie) Date: 03 Sep 2003 15:41:02 +0200 Subject: Packages in Erlang: new documentation In-Reply-To: References: <200309030143.h831hSBa301675@atlas.otago.ac.nz> Message-ID: Richard Carlsson writes: > Since the R9B release of Erlang, "packages" (hierarchical module > namespaces) have been available for testing by the Erlang community. > > It seems that the information about this, and how it works, has not > reached enough people. I have therefore written a new piece of > documentation about packages in Erlang, in the hope that it will > be better understood, and more people will try it out: > > http://www.csd.uu.se/projects/hipe/packages.html > > In particular, see the section about migrating code into packages. > > All comments appreciated, Do you have any real-program examples? From the spec alone packages seem to complicate things with no obvious gain. But perhaps seeing some pretty programs without "mymod_" strewn about them would provide the necessary temptation? I suppose that etags and distel will both need updating to resolve package names if they're to work on such code. But it looks like you can fully resolve packages from the source file alone, thanks to excluding 'import_all' - is that right? In Java you can't do that, e.g. in: import foo.*; import bar.*; ... { Baz.beer(); } To resolve 'Baz' you need to go running around the code-path to see if it's in the 'foo' or 'bar' package. (Fortunately this creates a thriving industry for fancy development tools. They run around figuring out all the things that can no longer be known by old-fashioned techniques like reading a source file :-) -Luke From richardc@REDACTED Wed Sep 3 15:55:17 2003 From: richardc@REDACTED (Richard Carlsson) Date: Wed, 3 Sep 2003 15:55:17 +0200 (MET DST) Subject: Packages in Erlang: new documentation In-Reply-To: References: <200309030143.h831hSBa301675@atlas.otago.ac.nz> Message-ID: On Wed, 3 Sep 2003, Luke Gorrie wrote: > Do you have any real-program examples? From the spec alone packages > seem to complicate things with no obvious gain. But perhaps seeing > some pretty programs without "mymod_" strewn about them would provide > the necessary temptation? Alas, not yet. Maybe when I release the next version of EDoc. > I suppose that etags and distel will both need updating to resolve > package names if they're to work on such code. Yes, and probably the emacs mode needs a little hacking by someone who knows how... > But it looks like you can fully resolve packages from the source file > alone, thanks to excluding 'import_all' - is that right? Yes. This was a design decision. You don't need to compile modules together in order to make them work. > In Java you can't do that, e.g. in: > > import foo.*; > import bar.*; > ... { > Baz.beer(); > } > > To resolve 'Baz' you need to go running around the code-path to see if > it's in the 'foo' or 'bar' package. And in Erlang, you could end up with some really strange runtime errors if you recompiled the system with a code path that differs from the one used by the original author or vendor. That's another important reason why that kind of import is not available. /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ "Having users is like optimization: the wise course is to delay it." -- Paul Graham From D.WILLIAMS@REDACTED Wed Sep 3 16:03:11 2003 From: D.WILLIAMS@REDACTED (WILLIAMS Dominic) Date: Wed, 3 Sep 2003 16:03:11 +0200 Subject: Packages in Erlang: new documentation Message-ID: > From: Richard Carlsson > > Since the R9B release of Erlang, "packages" (hierarchical module > namespaces) have been available for testing by the Erlang community. > > It seems that the information about this, and how it works, has not > reached enough people. I have therefore written a new piece of > documentation about packages in Erlang, in the hope that it will > be better understood, and more people will try it out: I plead guilty to having tried them out without giving feedback! So, here it is: They worked, as far as I could tell. I found them quite intuitively designed (I have used C++ namespaces and Java packages before). There is just one problem, from my point of view: they force one to import everything global (lists, io, etc.), or add a . in front of these modules (I couldn't get import_all to work for the global package). As I am sick of keeping track of #includes and imports, I enjoyed this not being necessary in Erlang. And I did not much like the look of code peppered with the . prefix (just a matter of taste). So, I am not using them for the moment. However, I have not written large volumes of Erlang code. Do those people who have feel a need to have packages? You seem to have survived without them so far! Regards, Dominic. From D.WILLIAMS@REDACTED Wed Sep 3 16:39:57 2003 From: D.WILLIAMS@REDACTED (WILLIAMS Dominic) Date: Wed, 3 Sep 2003 16:39:57 +0200 Subject: Packages in Erlang: new documentation Message-ID: While I am at it, and before the Erlang community commits to the concept of packages, I would like to argue in favour of Eiffel's concept of a posteriori name conflict resolution by renaming. The idea is that instead of conservatively putting every name into a package (which is just extra work, and only reduces the probability of conflict without eliminating it entirely), you can (locally) rename an existing module with which you have a name conflict, and use it under another name (an alias, if you will) in your own code (or in a specific module, or application). A single directive in (the Eiffel equivalent of) the (E)makefile is all you need. Very neat. Regards, Dominic. From richardc@REDACTED Wed Sep 3 16:55:39 2003 From: richardc@REDACTED (Richard Carlsson) Date: Wed, 3 Sep 2003 16:55:39 +0200 (MET DST) Subject: Packages in Erlang: new documentation In-Reply-To: References: Message-ID: On Wed, 3 Sep 2003, WILLIAMS Dominic wrote: > There is just one problem, from my point of view: they force one to > import everything global (lists, io, etc.), or add a . in front of > these modules [...] As I am sick of keeping track of #includes and > imports, I enjoyed this not being necessary in Erlang. An Erlang system without packages is very much like a Unix system with a command shell and its search path - a single, global namespace. It has its points - you can access a huge number of commands/modules with a small amount of typing - if you can remember the names for everything. This is one reason why many people like Unix. And also one of the main reasons why many people hate it. And even in Unix, you typically do not include _all_ possible directories that contain executables in your standard path. Lesser-used executables are usually referred to via their full path, such as /usr/sbin/ifconfig. But in Erlang, everything needs to be in the code path. The main points with a package system are: - you can use short, natural names for "local things" - you don't have to import local names and my motivation was to not have to see any more horrible module names such as: CosEventChannelAdmin_ProxyPushConsumer_impl oe_CosEventComm_CAdmin_impl sys_core_fold sasl_report_file_h orber_iiop_tracer_silent mnesia_frag_old_hash tool_file_dialog io_lib_fread inet_gethost_native hipe_sparc_ra_post_ls_fp hipe_x86_ra_ls_postconditions (also the long file names - add a ".beam" to the above), not to mention obscurities such as: pg2 sofs c si rb i uri (Hands up all of you who knew that these short names were already in use, and extra points if you can tell me what applications they belong to - no peeking!) For instance, how is anyone supposed to know that the name "tool_file_dialog" is already being used by the GS application, so you can't use it in your new wonderful 'tool' application? And why shouldn't I be able to use a local module called "vector" just because that name is already used in stdlib? I don't _want_ to have to name it "my_bloody_own_vector" (and type that name each time I make a call to it). Or reversely, why should the Erlang/OTP people not be able to add a module called "array" (for example) to stdlib, just because some customer already has a module by that name, and does not want to change their code in order to upgrade to the latest OTP release? I know that you can get a long way without a package system, but at the same time, these naming issues have always been annoying me. > And I did not much like the look of code peppered with the . prefix > (just a matter of taste). I absolutely agree: the . prefix notation is not recommended unless you really need it. Using -import(Module) is much better. Maybe we should also add a declaration -import_as(Module, Alias). /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ "Having users is like optimization: the wise course is to delay it." -- Paul Graham From richardc@REDACTED Wed Sep 3 17:06:39 2003 From: richardc@REDACTED (Richard Carlsson) Date: Wed, 3 Sep 2003 17:06:39 +0200 (MET DST) Subject: Packages in Erlang: new documentation In-Reply-To: References: Message-ID: On Wed, 3 Sep 2003, WILLIAMS Dominic wrote: > While I am at it, and before the Erlang community commits to the > concept of packages, I would like to argue in favour of Eiffel's > concept of a posteriori name conflict resolution by renaming. > > The idea is that instead of conservatively putting every name into a > package (which is just extra work, and only reduces the probability of > conflict without eliminating it entirely), you can (locally) rename an > existing module with which you have a name conflict, and use it under > another name (an alias, if you will) in your own code (or in a > specific module, or application). Yes, but it does not work in Erlang, because there your _cannot_ rename a module, since you cannot know if someone is going to call it via apply(M, F, [...]) or spawn(M, F, [...]). It is not possible to know in general what the M:s are, or even to which M the caller is actually referring (the first M, or the later added one that was renamed?) /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ "Having users is like optimization: the wise course is to delay it." -- Paul Graham From thomasl_erlang@REDACTED Wed Sep 3 17:42:50 2003 From: thomasl_erlang@REDACTED (Thomas Lindgren) Date: Wed, 3 Sep 2003 08:42:50 -0700 (PDT) Subject: Tail/Non tail recursion In-Reply-To: <200309030143.h831hSBa301675@atlas.otago.ac.nz> Message-ID: <20030903154250.13267.qmail@web41902.mail.yahoo.com> --- "Richard A. O'Keefe" wrote: > It seems a little unreasonable to call an operation > a "destructive" > update just because *some* (and definitely not all) > implementations > might have put something there first. "Unreasonable" seems a bit strong a word, I'd say. Surely you can see why one can reasonably choose to *do* call the update a destructive one? If not, I am willing to explain this further; but frankly, I'd prefer to let it rest. Best, Thomas __________________________________ Do you Yahoo!? The New Yahoo! Search - Faster. Easier. Bingo. http://search.yahoo.com From p0rj2el602@REDACTED Wed Sep 3 18:58:17 2003 From: p0rj2el602@REDACTED (Lon Willett) Date: 03 Sep 2003 18:58:17 +0200 Subject: Packages in Erlang: new documentation In-Reply-To: References: <200309030143.h831hSBa301675@atlas.otago.ac.nz> Message-ID: <14552-20289@sneakemail.com> On ons, 2003-09-03 at 14:34, Richard Carlsson richardc@REDACTED wrote: > Since the R9B release of Erlang, "packages" (hierarchical module > namespaces) have been available for testing by the Erlang community. > > It seems that the information about this, and how it works, has not > reached enough people. ... I have started to use it. One major problem for me is that I haven't been able to get the code coverage tools to work with it ("cover" module). Am I doing something wrong, or is this just a bug? One nice extension might be an "-import_as" directive, at least if it becomes common practice to use very long package names in order to avoid conflicts. e.g. One might write a package "some.very.long.package.name" with a module "format" that exports functions "foo" and "bar". While this works very prettily while writing the module (use "format:foo" to format a "foo"), users of the module may neither wish to have to use the full "some.very.long.package.name" nor to import a module named just "format". So it would be nice if they could use: -import_as(some.very.long.package.name.format,shortname_format). Then they could use "shortname_format:foo" and "shortname_format:bar" in their code. Just a thought (for whomever is hacking the package system)... /Lon From hal@REDACTED Wed Sep 3 21:27:27 2003 From: hal@REDACTED (Hal Snyder) Date: Wed, 03 Sep 2003 14:27:27 -0500 Subject: ei_rpc - pro and con, patch offered Message-ID: <87n0dlbrkw.fsf@ghidra.vail> Here are some comments, and a proposed patch, for ei_rpc, the C/C++ interface to OTP's RPC service. They are based on OTP-R9C-0, with tests run on FreeBSD-5.0. We expect to go ahead with ei_rpc on the current project. Btw, UBF lurks around the same problem space and may be introduced at any time. The main reason to use ei_rpc: If you already have working services or databases on OTP, they become readily accessible to C and C++ with little or no code added to the OTP parts of your enterprise. Within OTP, it is common to wrap a message-based or mnesia-based subsystem with an API so that outsiders do not need to access internal message and table implementations. Using rpc allows external nodes to use an existing functional API. Costs of ei_rpc: 1. C node must respond to ERL_TICK messages - while the response code is provided within the ei library, that code must be called by a listener thread or equivalent within the C node. 2. If thread-safety is a concern, the socket descriptor for each remote OTP node connection must be guarded by a mutexe. 3. If it is not acceptable for a client to block indefinitely on an rpc request, timeouts must be used. In that case, a response to an RPC call could belong to a previously issued query. In addition, responses can arrive out of order. Thus it is necessary to: a. carry transaction id in request and result and b. create client-side code for pairing requests with responses and scavenging both as needed The patch. Item 3a. can be eliminated if using the patch below, which also includes the nfds patch offered previously on this mailing list. The patch eliminates an apparently gratuitous setting of self.pid.num to the remote file descriptor. That gives us a 15-bit field in the C node (virtual) erlang_pid to use as transaction ID, thus: ecn.self.num = transaction_id; result = ei_rpc_to(&ecn, remote_fd, mod, func, args.buff, args.index); ... result = ei_rpc_from(&ecn, remote_fd, timeout_msec, &msg, &rpc_result); ... check for ERL_MSG result ... ... then match msg.to.num with transaction_id on query ... -------------- next part -------------- A non-text attachment was scrubbed... Name: ei_connect.c.patch Type: text/x-patch Size: 949 bytes Desc: ei_connect.c patch URL: -------------- next part -------------- Comments? From garry@REDACTED Wed Sep 3 21:55:08 2003 From: garry@REDACTED (Garry Hodgson) Date: Wed, 3 Sep 2003 15:55:08 -0400 (EDT) Subject: problem getting two erlangs to chat Message-ID: <2003090315551062618941@kestrel.sage.att.com> i'm having a problem getting two erl's to talk to each other. i suspect this'll be obvious to y'all, but i's escaping me. the server is written as a gen_server, with a start() that looks like: start() -> gen_server:start( { global, orbe }, orbe, [], [] ). it gets started with: erl -setcookie cookie -name orbe -s orbe start so far, so good. i want to control it via a separate program that invokes erlang to run a getProcesses() function: getProcesses() -> gen_server:call( { global, orbe }, getProcesses ). i run this one with: erl -setcookie cookie -name foo when i try and invoke getProcesses(), i get an error: (foo@REDACTED)1> orbe:getProcesses(). ** exited: {noproc,{gen_server,call,[{global,orbe},getProcesses]}} ** so i ping it, to see if the other node (on the same machine, incidentally) is alive: (foo@REDACTED)2> net_adm:ping( 'orbe@REDACTED' ). pong and after that, it works: (foo@REDACTED)3> orbe:getProcesses(). [{fred,cat,#Port<3942.37>,63229822226}, {barney,cat,#Port<3942.38>,63229822226}] so, the question is, what am i neglecting to do that the net_adm:ping() is doing for me? is this a reasonable mechanism for controlling a running erlang server? the intent is to have a script that will invoke something like "erl -s orbe status" or "erl -s orbe reset" to control the server, probably from someone else's CGI scripts (part of a bigger system, so i can't rewrite the whole thing or yaws or whatever). i'm open to suggestions as to a better way. thanks ---- Garry Hodgson, Technology Consultant, AT&T Labs Be happy for this moment. This moment is your life. From mlogan@REDACTED Wed Sep 3 23:28:42 2003 From: mlogan@REDACTED (Martin J. Logan) Date: 03 Sep 2003 16:28:42 -0500 Subject: problem getting two erlangs to chat In-Reply-To: <2003090315551062618941@kestrel.sage.att.com> References: <2003090315551062618941@kestrel.sage.att.com> Message-ID: <1062624521.17707.100.camel@dhcp-lom-194-186.futuresource.com> Garry, Before you do your net_adm:ping go ahead and type nodes(). What do you get? After you do your net adm ping I am assuming that nodes() will yield [foo@REDACTED, 'orbe@REDACTED']. The problem is most likely that your nodes are not connected, that is to say your net kernels don't have a record of one another. Cheers, Martin On Wed, 2003-09-03 at 14:55, Garry Hodgson wrote: > i'm having a problem getting two erl's to talk to each other. > i suspect this'll be obvious to y'all, but i's escaping me. > > the server is written as a gen_server, with a start() that looks like: > > start() -> > gen_server:start( { global, orbe }, orbe, [], [] ). > > it gets started with: > > erl -setcookie cookie -name orbe -s orbe start > > so far, so good. i want to control it via a separate program > that invokes erlang to run a getProcesses() function: > > getProcesses() -> > gen_server:call( { global, orbe }, getProcesses ). > > i run this one with: > > erl -setcookie cookie -name foo > > when i try and invoke getProcesses(), i get an error: > > (foo@REDACTED)1> orbe:getProcesses(). > ** exited: {noproc,{gen_server,call,[{global,orbe},getProcesses]}} ** > > so i ping it, to see if the other node (on the same machine, incidentally) > is alive: > > (foo@REDACTED)2> net_adm:ping( 'orbe@REDACTED' ). > pong > > and after that, it works: > > (foo@REDACTED)3> orbe:getProcesses(). > [{fred,cat,#Port<3942.37>,63229822226}, > {barney,cat,#Port<3942.38>,63229822226}] > > > so, the question is, what am i neglecting to do > that the net_adm:ping() is doing for me? > > is this a reasonable mechanism for controlling a > running erlang server? the intent is to have a script > that will invoke something like "erl -s orbe status" > or "erl -s orbe reset" to control the server, probably > from someone else's CGI scripts (part of a bigger system, > so i can't rewrite the whole thing or yaws or whatever). > > i'm open to suggestions as to a better way. > > thanks > > ---- > Garry Hodgson, Technology Consultant, AT&T Labs > > Be happy for this moment. > This moment is your life. From vances@REDACTED Wed Sep 3 23:40:25 2003 From: vances@REDACTED (Vance Shipley) Date: Wed, 3 Sep 2003 17:40:25 -0400 Subject: problem getting two erlangs to chat In-Reply-To: <2003090315551062618941@kestrel.sage.att.com> References: <2003090315551062618941@kestrel.sage.att.com> Message-ID: <20030903214025.GX35402@frogman.motivity.ca> Gary, The two nodes don't know about each other until you tell them. When you use the functions in net_adm the node contacts epmd to discover other noides known to that instance of epmd. This doesn't happen automatically at startup. You can check this by running erlang:nodes(), it will return an empty list. To make your system work the way you expect it to you can predefine the hosts containing nodes you want connected in an .hosts.erlang file. You can find this documented with the kernel:net_adm module. Then you put the net_adm:world() command in the $HOME/.erlang file. This tells erlang to look at the .hosts.erlang file on startup and contact epmd on each of the hosts mentioned in that file. Every node known to those epmds will now be known. While you're at it you can put any other initialization you wish in the .erlang file. If you always perform the same actions on startup put thise commands in here. For some fun on a rainy day look at stdlib:shell_default which allows you to create command syntax files so that in the shell you can do: 1> foo(). and have it run some long command(s). You can eliminate the "-setcookie cookie" options to your command lines if both nodes are started by the same user on the same host. The first node will create a $HOME/.erlang.cookie file containing the randomly chosen cookie (perms 400). The second node will use that file to set it's cookie. This also works with C nodes. -Vance Vance Shipley Motivity Telecom Inc. +1 519 240 3684 vances@REDACTED On Wed, Sep 03, 2003 at 03:55:08PM -0400, Garry Hodgson wrote: } } } i'm having a problem getting two erl's to talk to each other. } i suspect this'll be obvious to y'all, but i's escaping me. From ok@REDACTED Thu Sep 4 07:54:20 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Thu, 4 Sep 2003 17:54:20 +1200 (NZST) Subject: Packages in Erlang: new documentation Message-ID: <200309040554.h845sKqd310378@atlas.otago.ac.nz> On Wed, 3 Sep 2003, WILLIAMS Dominic wrote: > While I am at it, and before the Erlang community commits to the > concept of packages, I would like to argue in favour of Eiffel's > concept of a posteriori name conflict resolution by renaming. I take it that he is referring to something like -name_module(snark, remote.module.name.called.boojum). after which the module can refer to snark:start() and start a boojum. Yes, but it does not work in Erlang, because there your _cannot_ rename a module, since you cannot know if someone is going to call it via apply(M, F, [...]) or spawn(M, F, [...]). It is not possible to know in general what the M:s are, or even to which M the caller is actually referring (the first M, or the later added one that was renamed?) Clearly I must have misunderstood *someone*, because to make what I thought was proposed work, all you have to do is have a local table of renamings in the module, and then have apply/3 and spawn/3 and so on look in that table. I note that Haskell has moved from a flat module namespace to a hierarchical module namespace comparatively recently. Ada 95 introduced nested packages to Ada, with some interesting and complex visibility rules. I note that Common Lisp moved in the other direction: the original package design had nested packages, but the one adopted for the standard didn't. Similarly, the original book on SETL had a complex nested package system, but that was later dropped. >From a survey of languages, one finds that dotted namespaces are a popular idea but seem to be surprisingly complex in practice; frankly they are something that should NEVER be released until there has been quite a lot of experimentation (and ideally a formal specification). One of the best things David Warren ever did for Quintus was to keep on saying NO to the module system designs that others (principally David Bowen) came up with until finally there was one that was simple enough. There are a number of things about that web page that bother me. The first is that while the noun "package" is used often, there doesn't seem to be any referent for it. There are module objects, and there are name objects (the "case X of foo.bar.baz ->" example suggests that dotted names are just symbols). But there doesn't seem to be any *Erlang* object for a "package" to refer to. Packages appear to have no properties and enter into no relationships; there are really only package *names*. In short, from the inside, there appears to be no significant difference between a module name like foo_bar_baz and a module name like foo.bar.baz. That's the first thing that bothers me: language that confuses me by talking about packages when there are only dotted module names. The second is that there is a fixed relationship between a module name and a set of places to look for it. This has proven to be a real pain in Java, where you want a development version of a package and a stable version, but because they are versions of the same package, they get the same mapping onto directories. Amongst other extremely nasty consequences, as far as Erlang is concerned, 'forx' and 'forX' are two different module names, but on some file systems (Windows) they must map to the same file name. There's another nasty consequence. Consider the following example: 1> c('*foo*'). {ok,'*foo*'} 2> l('*foo*'). {module,'*foo*'} 3> '*foo*':f(). where '*foo*.erl' is -module('*erl*'). -export([f/0]). f() -> 27. Erlang is one language, with one set of rules about what can be a symbol. ANY symbol can in principle be used as a module name. But there are several file systems: UNIX has one set of rules for what can be used in a file name ('/' may not, '\0' may not, but any other character may be), Windows has another set of rules, RiscOS has yet another set of rules, other operating systems have yet other rules. Since the set of operating systems is open-ended, if you insist on mapping Erlang module names directly to file names, NOBODY CAN EVER KNOW WHAT THE SET OF PORTABLE ERLANG MODULE NAMES IS! Nobody can even know how long an Erlang module name may be: is the limit 8 or 10 or 27 or 251 or what? The only programming languages I've seen where this problem is satisfactorily addressed are Common Lisp (the "defsystem" facility, although it didn't make it into the standard) and Eiffel (the "LACE" facility, which I _hope_ will make it into the ECMA standard for Eiffel). Let me put this as bluntly as I possibly can: While there may be a default mapping from Erlang module names to files, it must be possible for someone installing a module or package of modules to put each file exactly where s/he wants without _any_ constraint on how files are named. Amongst other things, as soon as you step outside ASCII, it's entirely possible that the file system used by the author of a module will encode characters one way (Latin-1, say) while the file system used by the installed may encode characters another way (UTF-8, say). There are a couple of other things that bother me, but those are the big ones. I've always regarded the mapping from module names to file names as a short-term makeshift, and with the introduction of dotted names the idea of a fixed mapping from module names to file names is now very definitely an idea whose time has *GONE*. (The possible loopholes caused by a search path make me queasy. That's an idea whose time has gone too.) From vlad_dumitrescu@REDACTED Thu Sep 4 08:55:24 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Thu, 4 Sep 2003 08:55:24 +0200 Subject: Packages in Erlang: new documentation References: <200309040554.h845sKqd310378@atlas.otago.ac.nz> Message-ID: From: "Richard A. O'Keefe" >> Yes, but it does not work in Erlang, because there your _cannot_ >> rename a module, since you cannot know if someone is going to >> call it via apply(M, F, [...]) or spawn(M, F, [...]). It is not >> possible to know in general what the M:s are, or even to which >> M the caller is actually referring (the first M, or the later added >> one that was renamed?) > > Clearly I must have misunderstood *someone*, because to make what I > thought was proposed work, all you have to do is have a local table > of renamings in the module, and then have apply/3 and spawn/3 and so > on look in that table. Hi, While I think it would be a nice solution, I don't think it works that easily. Please anyone correct me if I am wrong. For the first, that would mean that every remote call will have to check first the internal module table for a rename. That would make these calls much slower. Then there must be a check for non-overlapping renames, because that would open for some hard to find bugs. That would be at compile-time, so probably not a problem. Again, if a module name is sent as a function argument, the local name wouldn't make sense to any other module. Sure, we could have a function to retrieve the complete name, but personally I feel it's more error-prone than elegant. Finally, what about functional objects? The environment for a closure would need to include the rename table from the defining module. These problems are solvable, but look like are imposing more restrictions for the programmer than they remove. >In short, from the inside, there appears to be no significant difference >between a module name like foo_bar_baz and a module name like foo.bar.baz. Only that locally you can use baz:fun(...) instead of the full module name. And also that maybe one wants/needs to rename the 'foo' application, and then not all module names have to be updated. best regards, Vlad From richardc@REDACTED Wed Sep 3 14:34:49 2003 From: richardc@REDACTED (Richard Carlsson) Date: Wed, 3 Sep 2003 14:34:49 +0200 (MET DST) Subject: Packages in Erlang: new documentation In-Reply-To: <200309030143.h831hSBa301675@atlas.otago.ac.nz> References: <200309030143.h831hSBa301675@atlas.otago.ac.nz> Message-ID: Since the R9B release of Erlang, "packages" (hierarchical module namespaces) have been available for testing by the Erlang community. It seems that the information about this, and how it works, has not reached enough people. I have therefore written a new piece of documentation about packages in Erlang, in the hope that it will be better understood, and more people will try it out: http://www.csd.uu.se/projects/hipe/packages.html In particular, see the section about migrating code into packages. All comments appreciated, /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ From ulf.wiger@REDACTED Thu Sep 4 11:20:56 2003 From: ulf.wiger@REDACTED (=?ISO-8859-1?Q?Ulf_Wiger_=28=C4L2/EAB=29?=) Date: Thu, 4 Sep 2003 11:20:56 +0200 Subject: Packages in Erlang: new documentation Message-ID: <76E5F712842F5F49A35738622BAA0F4F9EA6F0@ESEALNT442.al.sw.ericsson.se> From: Richard Carlsson [mailto:richardc@REDACTED] >It seems that the information about this, and how it works, has not >reached enough people. I have therefore written a new piece of >documentation about packages in Erlang, in the hope that it will >be better understood, and more people will try it out: > > http://www.csd.uu.se/projects/hipe/packages.html > >In particular, see the section about migrating code into packages. > >All comments appreciated, I'll briefly report my experiences with packages so far: I decided to try packages in a hobby project, called CyberAthletics. It's a project sponsored by the Swedish Athletics Association aiming at providing wireless services to the audience at Athletics competitions. The dotted naming convention did offer a relief from the namespace problem. Examples from my CyberAthletics (or "cath" for short) application: cath.server.contest .athlete .control .db .event .schedule .install .application .client.client .gui .gs.browser .window .contest I actually like the -import() clauses. I think they add useful information, and the discipline it requires is beneficial IMHO. I dislike the .lists notation, and haven't used it. A slight nuisance is that the path under src/ becomes cath/server/... and also under src/ (following the OTP convention) is cath.app.src. This interferes with tab completion, and I also feel that there is one level too many in the directory structure. I'm not thrilled by the idea of tying module names to directory structure closer than before. I have yet to come up with a better scheme, though. I modified systools_make.erl in order to make it handle dotted module names while building boot scripts. I noted that embedded code loading doesn't work, but for this, one has to modify erl_prim_loader -- doable, but I haven't done it. The 'builder' contrib at jungerl also understands dotted names. All in all I find packages to be an improvement, even though some work remains in order to integrate it fully with OTP. /Uffe From p0rj2el602@REDACTED Thu Sep 4 11:37:08 2003 From: p0rj2el602@REDACTED (Lon Willett) Date: 04 Sep 2003 11:37:08 +0200 Subject: Parameterised modules In-Reply-To: References: Message-ID: <3230-90099@sneakemail.com> Hi, On m?n, 2003-09-01 at 11:58, Sean Hinde sean.hinde@REDACTED wrote: > A few thoughts on the proposal for parameterised modules as presented > at the Erlang Workshop on Friday. > ... I've been thinking about that presentation too. I think that these could be very useful in far more places than the examples given. I definitely want them. > So in summary the two weaknesses I see are: > > 1. There is no way to provide variable numbers of instantiation > parameters. > 2. There is no way to provide default values for instantiation > parameters. ... > Thoughts anyone? ... How about static functions? There is no reason that the compiler couldn't recognise functions that don't use any of the instance variables, and allow them to be called directly. One could then write one's own version of new, e.g. -module(foo,[X,Y]). -export([new/1,...]). new(UserX) -> new(UserX, defaultY). ... Then the user could call either foo:new(X,Y) or foo:new(X). This seems like a very natural way to do it, and users can write arbitrarily complex versions of new if they want keywords, etc. I suppose an -export_static directive could even be implemented, if it's thought to be useful, but I don't see this as important. And while on the topic of parameterised modules, an issue that I am concerned with is the handling of code change. I am not convinced that the proposed handling is correct. I am not even sure what the _right_thing_ is. Abstract modules really have (at least) two interfaces: one is the behaviour(s) that they implement, and the other is their construction ("new" function(s)). Generally these are distinct: the "new" interface will often be internal to a package, or otherwise specialised for the module's static clients, i.e. the code that knows specifically what the module does. The instances are (generally) passed to code that only knows that it is a module implementing some behaviour. With the current proposal, any changes in instance variables break the code change, or at least remove any advantages to it. Yet changes to the internals of a package are precisely the sort of thing one wants to do with code change. e.g. One has an abstract module "foo" which implements various behaviours. Instances of it are only created by the module "bar", but are used by various other pieces of code which are unrelated, except for understanding the behaviours implemented by "foo". One wishes to support code change for the modules "foo" and "bar". With the proposed system, the options are: (1) Make sure that instance variables don't change in number, order, or definition between versions. (2) Make sure that all instances of the module are discarded when the code change is performed. Option #1 is rather restrictive. When writing version 1 of the code, one must anticipate any changes that will be made. The customer needs parameterised logging added for a couple of special cases? Then it needs to be kludged in, since one can't add parameters to "foo". Option #2 is more general, but means that the fact that old instances of "foo" use the new code is useless. Even worse is the case where one of the instance variables has changed subtly in definition, and one (incorrectly) fails to discard all existing instances of "foo". Then the old instances will misbehave in a very hard to diagnose fashion, rather than just failing. Perhaps these problems can be lived with, but I think that they should be considered. Ideally, I think one would like an explicit code change interface. i.e. one can write a static "code_change" function which is automatically invoked when an old instance of the module is used, and which returns a new instance to be used. i.e. foo:code_change(OldVersion,OldVariableList) calls foo:new with the correct updated parameters, and this value magically replaces the old instance. Of course, this is asking quite a bit more of the implementation, and may impact efficiency. Anyone else have any thoughts on this? /Lon From joachim.durchholz@REDACTED Thu Sep 4 13:14:03 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Thu, 04 Sep 2003 13:14:03 +0200 Subject: Packages in Erlang: new documentation In-Reply-To: <76E5F712842F5F49A35738622BAA0F4F9EA6F0@ESEALNT442.al.sw.ericsson.se> References: <76E5F712842F5F49A35738622BAA0F4F9EA6F0@ESEALNT442.al.sw.ericsson.se> Message-ID: <3F571E7B.5070207@web.de> Ulf Wiger (?L2/EAB) wrote: > I'm not thrilled by the idea of tying module names to directory > structure closer than before. I have yet to come up with a better > scheme, though. The important thing is that, given a fully qualified module name, module files should be easy to find. Search paths are a horror in this regard, unless you have generous tool support. Search paths combined with subdirectories are horror squared, even with tool support (I've been working with Java where this scenario is true, and it's most definitely not fun trying to find out in which of a gazillion subdirectories a particular module is). To avoid these hassles, I'd like to place all module files of a package in a single directory. Module "remote.module.name.called.boojum" would then reside in file "remote.module.name.called.boojum.erl". This might get into trouble with operating systems that don't have long file names, but I just hope that we can ignore these today... Regards, Jo From Bengt.Kleberg@REDACTED Thu Sep 4 14:44:51 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Thu, 04 Sep 2003 14:44:51 +0200 Subject: free_vars/1 In-Reply-To: <76E5F712842F5F49A35738622BAA0F4F9EA6F0@ESEALNT442.al.sw.ericsson.se> References: <76E5F712842F5F49A35738622BAA0F4F9EA6F0@ESEALNT442.al.sw.ericsson.se> Message-ID: <3F5733C3.3030401@ericsson.com> greetings, i have been using the function free_vars/1 (see end of email) by Richard Carlsson(?). it is very helpful when refactoring code. unfortunatly it throws an error when given a macro. erl_parse:parse_exprs/1 returns {error, {Line, erl_parse, Reason}} when fed a macro. my solution has been to change macros to atoms, like this: macros_to_atoms( [] ) -> []; macros_to_atoms( [{'?',_Nr}, {_Type, Nr, Macro}|T] ) -> [{atom, Nr, Macro} | macros_to_atoms( T )]; macros_to_atoms( [H|T] ) -> [H | macros_to_atoms( T )]. before calling erl_parse:parse_exprs/1. is there a better way? bengt %% @spec free_vars(Text::string()) -> string() %% @equiv free_vars(Text, 1) free_vars(Text) -> free_vars(Text, 1). %% @spec free_vars(Text::string(), Line::integer()) -> string() free_vars(Text, StartLine) -> %% StartLine/EndLine may be useful in error messages. {ok, Ts, EndLine} = erl_scan:string(Text, StartLine), Ts1 = lists:reverse([{dot, EndLine} | strip(lists:reverse(Ts))]), Ts2 = macros_to_atoms( Ts1 ), case erl_parse:parse_exprs(Ts2) of {ok, Es} -> E = erl_syntax:block_expr(Es), E1 = erl_syntax_lib:annotate_bindings(E, ordsets:new()), {value, {free, Vs}} = lists:keysearch(free, 1, erl_syntax:get_ann(E1)), Vs; {error, {_Line, erl_parse, Reason}} -> erlang:throw( {error, io_lib:format("~s", [Reason])} ) end. strip([{',', _} | Ts]) -> strip(Ts); strip([{';', _} | Ts]) -> strip(Ts); strip([{'.', _} | Ts]) -> strip(Ts); strip([{'|', _} | Ts]) -> strip(Ts); strip([{'=', _} | Ts]) -> strip(Ts); strip([{'dot', _} | Ts]) -> strip(Ts); strip([{'->', _} | Ts]) -> strip(Ts); strip([{'||', _} | Ts]) -> strip(Ts); strip([{'of', _} | Ts]) -> strip(Ts); strip(Ts) -> Ts. From luke@REDACTED Thu Sep 4 15:03:23 2003 From: luke@REDACTED (Luke Gorrie) Date: 04 Sep 2003 15:03:23 +0200 Subject: free_vars/1 In-Reply-To: <3F5733C3.3030401@ericsson.com> References: <76E5F712842F5F49A35738622BAA0F4F9EA6F0@ESEALNT442.al.sw.ericsson.se> <3F5733C3.3030401@ericsson.com> Message-ID: Bengt Kleberg writes: > greetings, > > i have been using the function free_vars/1 (see end of email) by > Richard Carlsson(?). it is very helpful when refactoring > code. unfortunatly it throws an error when given a > macro. erl_parse:parse_exprs/1 returns {error, {Line, erl_parse, > Reason}} when fed a macro. > > my solution has been to change macros to atoms, like this: > > macros_to_atoms( [] ) -> > []; > macros_to_atoms( [{'?',_Nr}, {_Type, Nr, Macro}|T] ) -> > [{atom, Nr, Macro} | macros_to_atoms( T )]; > macros_to_atoms( [H|T] ) -> > [H | macros_to_atoms( T )]. > > before calling erl_parse:parse_exprs/1. > > is there a better way? Are you doing this via Distel? (Distel has a command to automate this refactoring.) This is taken care of in the CVS version of Distel. My solution was to remove all the macros with some Elisp code before sending it to Erlang and Richard's analysis program. Specifically, "?ANYTHING" becomes "deadmacro". (It's okay to mutilate the code arbitrarily so long as the set of free variables is preserved.) This is not "correct" in that it won't handle the case where real macroexpansion would introduce more free variables, but anyone who codes like that deserves that they get. (Hey, don't I sound like a real software vendor? :-) I can do a new Distel release if that would be helpful. I haven't bothered yet because IIRC this is the only change since version 3.3. Or if you want to do a quick "hot fix", you can just replace your erl-service.el with the one attached below. (Thanks to Tobbe T?rnkvist for using the refactoring feature enough to motivate the fix :-) Cheers, Luke -------------- next part -------------- A non-text attachment was scrubbed... Name: erl-service.el Type: application/emacs-lisp Size: 33544 bytes Desc: erl-service.el with refactoring-with-macros fix URL: From luke@REDACTED Thu Sep 4 15:19:07 2003 From: luke@REDACTED (Luke Gorrie) Date: 04 Sep 2003 15:19:07 +0200 Subject: free_vars/1 In-Reply-To: References: <76E5F712842F5F49A35738622BAA0F4F9EA6F0@ESEALNT442.al.sw.ericsson.se> <3F5733C3.3030401@ericsson.com> Message-ID: Luke Gorrie writes: > Bengt Kleberg writes: > > > i have been using the function free_vars/1 (see end of email) by > > Richard Carlsson(?). > > My solution was to remove all the macros with some Elisp code before > sending it to Erlang and Richard's analysis program. Ahem. Your solution is actually better than mine, since it operates on properly tokenized data whereas mine is regexp'ing text more... "heuristically". As Jamie Zawinski wisely said, Some programmers when faced with a problem think, "I know, I'll use a regular expression." Now they have two problems. I will switch over to your way in the next Distel version :-) Cheers, Luke From richardc@REDACTED Thu Sep 4 15:21:41 2003 From: richardc@REDACTED (Richard Carlsson) Date: Thu, 4 Sep 2003 15:21:41 +0200 (MET DST) Subject: free_vars/1 In-Reply-To: References: <76E5F712842F5F49A35738622BAA0F4F9EA6F0@ESEALNT442.al.sw.ericsson.se> <3F5733C3.3030401@ericsson.com> Message-ID: On Thu, 4 Sep 2003, Luke Gorrie wrote: > Bengt Kleberg writes: > > > i have been using the function free_vars/1 (see end of email) by > > Richard Carlsson(?). it is very helpful when refactoring > > code. unfortunatly it throws an error when given a > > macro. erl_parse:parse_exprs/1 returns {error, {Line, erl_parse, > > Reason}} when fed a macro. > > > > my solution has been to change macros to atoms, like this: > > > > macros_to_atoms( [] ) -> > > []; > > macros_to_atoms( [{'?',_Nr}, {_Type, Nr, Macro}|T] ) -> > > [{atom, Nr, Macro} | macros_to_atoms( T )]; > > macros_to_atoms( [H|T] ) -> > > [H | macros_to_atoms( T )]. > > > > before calling erl_parse:parse_exprs/1. > > > > is there a better way? > > Are you doing this via Distel? (Distel has a command to automate this > refactoring.) > > This is taken care of in the CVS version of Distel. My solution was to > remove all the macros with some Elisp code before sending it to Erlang > and Richard's analysis program. Specifically, "?ANYTHING" becomes > "deadmacro". (It's okay to mutilate the code arbitrarily so long as > the set of free variables is preserved.) If you take a look at the module 'epp_dodger.erl' in the syntax_tools contribution, it does a similar trick to get code containing macros past the parser. (It handles most "sane" uses of macros.) You might be able to use it directly, or just steal some parts of the code. /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ "Having users is like optimization: the wise course is to delay it." -- Paul Graham From luke@REDACTED Thu Sep 4 15:32:14 2003 From: luke@REDACTED (Luke Gorrie) Date: 04 Sep 2003 15:32:14 +0200 Subject: free_vars/1 In-Reply-To: References: <76E5F712842F5F49A35738622BAA0F4F9EA6F0@ESEALNT442.al.sw.ericsson.se> <3F5733C3.3030401@ericsson.com> Message-ID: Richard Carlsson writes: > If you take a look at the module 'epp_dodger.erl' in the syntax_tools > contribution, it does a similar trick to get code containing macros past > the parser. (It handles most "sane" uses of macros.) You might be able > to use it directly, or just steal some parts of the code. Also note that syntax_tools is in the Jungerl, so if you want to use it with Distel you may not have to do a separate download. For Distel I always have an Erlang node running like this: $JUNGERL/bin/jerl -sname x -pa $OUR_SYSTEM/lib/*/ebin/ 'jerl' is just a wrapper to include all the Jungerl code in the code path (so you get syntax_tools), and the -pa with wildcard adds all the code in our system to the code path (so that the TAGS-like stuff always works.) Cheers, Luke From luke@REDACTED Thu Sep 4 15:47:34 2003 From: luke@REDACTED (Luke Gorrie) Date: 04 Sep 2003 15:47:34 +0200 Subject: free_vars/1 In-Reply-To: <3F5733C3.3030401@ericsson.com> References: <76E5F712842F5F49A35738622BAA0F4F9EA6F0@ESEALNT442.al.sw.ericsson.se> <3F5733C3.3030401@ericsson.com> Message-ID: Bengt Kleberg writes: > %% @spec free_vars(Text::string()) -> string() This declaration is totally wrong actually. I hacked Richard's function to return a list of atoms instead of a string, but didn't update the type declaration (until now). Someone should write a static type checker to find these problems. ;-) Cheers, Luke From D.WILLIAMS@REDACTED Thu Sep 4 16:03:17 2003 From: D.WILLIAMS@REDACTED (WILLIAMS Dominic) Date: Thu, 4 Sep 2003 16:03:17 +0200 Subject: Packages in Erlang: new documentation Message-ID: Richard Carlsson wrote: > I absolutely agree: the . prefix notation is not recommended unless > you really need it. Using -import(Module) is much better. Maybe we > should also add a declaration -import_as(Module, Alias). But later, when I described the Eiffel renaming scheme, you wrote: > Yes, but it does not work in Erlang, because there your _cannot_ > rename a module, since you cannot know if someone is going to > call it via apply(M, F, [...]) or spawn(M, F, [...]). It is not > possible to know in general what the M:s are, or even to which > M the caller is actually referring (the first M, or the later added > one that was renamed?) Hmm. You suggested -import_as(Module,Alias) yourself. Is that any different? Or did you suggest it before having thought of those difficulties? Anyway (Eiffel philosophy again), shouldn't things be hard for compiler programmers, not application programmers ? ;-) Oh, and I very much share the concern voiced by others about tying in the package structure to the filesystem. In addition to reasons already given, I dream of a Smalltalk-like IDE for Erlang, where the code is not in files at all (and is interpreted, or compiled on-the-fly). Regards, Dominic. From olgeni@REDACTED Thu Sep 4 16:50:13 2003 From: olgeni@REDACTED (Jimmy Olgeni) Date: Thu, 4 Sep 2003 16:50:13 +0200 (CEST) Subject: debugger-2.2 and online help Message-ID: <20030904164737.H38331@dev1.localdomain.net> Hi there, There's something wrong with the debugger's online help: it looks for $WHATEVER/lib/debugger-2.2/doc/index.html, but the index file actually lives in doc/html/index.html... candidate fix for the next release :) -- jimmy From Johan.Blom@REDACTED Thu Sep 4 17:12:48 2003 From: Johan.Blom@REDACTED (Johan.Blom@REDACTED) Date: Thu, 04 Sep 2003 17:12:48 +0200 Subject: Inets/http In-Reply-To: <1F42BB97D787C048BCC519FF28048AC367FB@galileo.ifoni.com> References: <1F42BB97D787C048BCC519FF28048AC367FB@galileo.ifoni.com> Message-ID: <3F575670.9000105@mobilearts.se> Hi Rudolph, sorry for not responding earlier, been busy... I don't know about support, nor unit tests, but as I once wrote it I do feel a bit responsible. Issue 1: Well, I think this is pretty clear, see Section 14.30 in RFC2616 that states that the Location header MUST use the absoluteURI format. Furthermore, strict standard compliance is something I strive for thus the comment in the source. To fix your problem I would suggest to add a "relax" option for a less strict interpretation and then add behaviours as needed. Issue 2: You are aboslutely right. I have updated the cvs tree at sowap.sf.net with fixes. Regards Johan Blom Mobile Arts Rudolph van Graan wrote: > Hi all, > > Today I have a question regarding the support of the http module in > inets. I've recently had to write an application that uses http to > retrieve some information. I found some issues with the way the code > deals with a) Microsoft IIS redirects [a known issue] and b) handling of > spaces in GET parameters. I've mailed the author of http requestion help > building a patch to address these issues, but to date I had no response. > So, how does one report bugs on http and how can I submit possible > fixes? I couldn't find any reference in the code to standard unit tests, > so I don't know if my patch broke anything. Does someone know of tests > written for http? > > Issue 1: > > The first issue has to do with the comments at the top of the http.erl > module: > > %% Note: > %% - Some servers (e.g. Microsoft-IIS/5.0) may sometimes not return a > proper > %% 'Location' header on a redirect. > %% The client will fail with {error,no_scheme} in these cases. > > Suppose the url one is trying to fetch is > "http://some.server.com/blah.asp" and it tries to redirect to "blie.asp" > on the same server, the Location header field contains "blie.asp" > instead of "http://some.server.asp/blie.asp". Is this correct? I've > found that when an IIS 5.0 server redirects, it does not expand the URL > back to its complete form. I *have* to get http.erl to work properly > with someone else's website, so I've started at trying to fix this > problem [by letting httpc_handler.erl] fix the Location when it is in > this state. I've built a simple fix, but I cannot regression test it > using the unittests for the module, nor do I know how to include this in > the actual erlang distribution. > > > Issue 2: > > The other problem has to do with a URL that looks like this > "http://some.server.com/blah.asp?data=Some%20Text" > > The %20 means a space in the data. Now, http "prepares" the url and then > change the %20 into a space, so the actual > URL requested from the Web server is > "http://some.server.com/blah.asp?data=Some Text" which clearly is not > properly formed. I feel that the code should in fact change any embedded > spaces into the hex version, but not change embedded hex characters back > to the actual form. > > Any suggestions? > > Thank you for all the help in the past. > > Rgds, > > Rudolph > > From richardc@REDACTED Thu Sep 4 17:15:37 2003 From: richardc@REDACTED (Richard Carlsson) Date: Thu, 4 Sep 2003 17:15:37 +0200 (MET DST) Subject: Packages in Erlang: new documentation In-Reply-To: References: Message-ID: On Thu, 4 Sep 2003, WILLIAMS Dominic wrote: > Richard Carlsson wrote: > > > I absolutely agree: the . prefix notation is not recommended unless > > you really need it. Using -import(Module) is much better. Maybe we > > should also add a declaration -import_as(Module, Alias). > > But later, when I described the Eiffel renaming scheme, you wrote: > > > Yes, but it does not work in Erlang, because there your _cannot_ > > rename a module, since you cannot know if someone is going to > > call it via apply(M, F, [...]) or spawn(M, F, [...]). It is not > > possible to know in general what the M:s are, or even to which > > M the caller is actually referring (the first M, or the later added > > one that was renamed?) > > Hmm. You suggested -import_as(Module,Alias) yourself. Is that any > different? Or did you suggest it before having thought of those > difficulties? Ah, but these two are very different things. When you use a declaration "-import(package.module)" in the package system as it is today, this only affects the expansion of explicit remote calls on the form "module:function(...)", which are rewritten by the compiler to "package.module:function(...)". A declaration "-import_as(package.module,alias)" would only change the expansion (within that particular module) to "package.alias:function(...)". In short: this works because it only happens in the specific syntactic context of a remote call. Other atoms are not affected, so the following does *not* work: -import(my.own.foo). ... M = foo, ... M:bar(...) because the compiler cannot (in the general case) know that the occurrence of the atom 'foo' will be used as the name of a module and nothing else. It is unfortunate that we have to rely on the context in this way, but it is a consequence of how the Erlang language was constructed, and there is no workaround. There is a similar problem with local function calls. The following is correct: X = my_function(Y) (if my_function/1 exists), but the following will cause a runtime error: F = my_function, X = F(Y) because the *value* F is just an atom, not a function. The first case only works because the compiler has recognized the syntax "(A1,...,An)" as a special case, and rewritten it to (in effect) "(fun /)(A1,...,An)" when going to the core language. (Note that if Erlang had used variables for function and module names, lexically speaking, instead of atoms, we would not have these problems.) In the suggested case of dynamic renaming in spawn/apply, however, the problem is that there is no context at all! We have no type system that can tell us that a particular value is a "name" that can and should be undergo renaming. Names are just atoms - and in some cases they are even strings that become concatenated and then turned into atoms. So if one module passes an atom to another module (maybe through a long chain of indirections, storing in data structures, etc.), and the recipient takes this atom and uses it in a call to 'spawn(M,F,[...])', we cannot tell whether the atom ought to be renamed according to the local renaming table of the module that calls 'spawn', or according to that of the module where the atom originated. And we can't just rename an atom unless we can prove that it will _only_ be used as a module name in calls - what if the atom is _also_ used for other things, such as naming a server, or being part of a file name? This is why, in the final expanded code, all module names need to be "absolute references", i.e., fully qualified. > Anyway (Eiffel philosophy again), shouldn't things be hard for > compiler programmers, not application programmers ? ;-) Trust me on this: they already are. ;-( > Oh, and I very much share the concern voiced by others about tying in > the package structure to the filesystem. Well, I have to say like Ulf did that I just don't know any other good solution. The precise connection between the naming of packages and the storage of files can always be changed by hacking the code loader. But I think that anyone who considers subdirectories to be a bad idea for storing code should first of all take some time to think about why typical file systems work the way they do, and why they have not yet been replaced with "something better". For example, the HiPE compiler consists of some 150 modules. I would like to *not* have to have the object files in a single directory. We already have the source files in separate subdirectories, for the sake of sanity. I fail to see what is so good about a single directory stuffed with hundreds of files with very long names. I agree that search paths are evil. The Erlang/OTP default search path contains about 45 entries! And yet all of these are subdirectories of the "lib" directory. With packages, it could be just a single entry in the path. /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ "Having users is like optimization: the wise course is to delay it." -- Paul Graham From cpressey@REDACTED Thu Sep 4 18:55:16 2003 From: cpressey@REDACTED (Chris Pressey) Date: Thu, 4 Sep 2003 09:55:16 -0700 Subject: Packages in Erlang: new documentation In-Reply-To: References: <200309030143.h831hSBa301675@atlas.otago.ac.nz> Message-ID: <20030904095516.16352df9.cpressey@catseye.mine.nu> On Wed, 3 Sep 2003 14:34:49 +0200 (MET DST) Richard Carlsson wrote: > Since the R9B release of Erlang, "packages" (hierarchical module > namespaces) have been available for testing by the Erlang community. > > It seems that the information about this, and how it works, has not > reached enough people. I have therefore written a new piece of > documentation about packages in Erlang, in the hope that it will > be better understood, and more people will try it out: > > http://www.csd.uu.se/projects/hipe/packages.html > > In particular, see the section about migrating code into packages. > > All comments appreciated, > > /Richard Well, I was doing a overhaul of OpenFlax anyway, so I decided to packagize it to see what it's like. It used to look like: openflax-xxxx.yyyy/src/openflax.erl openflax-xxxx.yyyy/src/openflax_log.erl openflax-xxxx.yyyy/src/openflax_http.erl openflax-xxxx.yyyy/src/openflax_http_request.erl openflax-xxxx.yyyy/src/openflax_http_response.erl (etc, and) openflax_mod-xxxx.yyyy/src/openflax_mod_file.erl openflax_mod-xxxx.yyyy/src/openflax_mod_upload.erl (etc) Now it looks like: openflax-xxxx.yyyy/src/openflax/app.erl openflax-xxxx.yyyy/src/openflax/log.erl openflax-xxxx.yyyy/src/openflax/http/middleman.erl openflax-xxxx.yyyy/src/openflax/http/request.erl openflax-xxxx.yyyy/src/openflax/http/response.erl (etc, and) openflax_mod-xxxx.yyyy/src/openflax/mod/file.erl openflax_mod-xxxx.yyyy/src/openflax/mod/upload.erl (etc) ...with a similar tree under ebin/ (i.e. I don't prefer to put source, object, and doc files all in the same directory, I think it's messy.) The deep directory structure caused some frustration with my build scripts (which were of course originally hacked up to expect a nice flat workspace,) but nothing insurmountable. All in all it's not as bad as I feared. My experience is similar to Ulf's in many respects. I left most of the references fully qualified (e.g. I just changed openflax_log:write to openflax.log:write rather than shortening it to log.write.) Intuitively I expected to be able to import not just a module but an entire package (e.g. to say -import(openflax.http) and then say http.request:collect) but it looks like that's not supported. In this sense, and in some that Richard O. mentioned, it just doesn't "feel" very hierarchical. The combination of flat code path and package hierarchy is... interesting. Probably too complex as it stands, but also it's kind of convenient (for me) that the openflax_mod application can stick modules in openflax's packagespace, just like without the hierarchy. If the code path were eliminated, things would get trickier (since I do want these to be seperate applications - openflax is the base which is minimal and tight, and openflax_mod is the set of addons which is featureful and necessarily somewhat less tight.) I also wonder about some stylistic issues. 'openflax' was effectively renamed 'openflax.app' - I could have chosen 'openflax.main' or something else, or just left it 'openflax', but I didn't know how having a module name the same as a package name would have affected things. I'm not sure if the mapping of module names to file names is a hard problem, or just a messy one. It might be nice to have some specific rules in that regard (e.g. module names must be lower-case alphanumeric plus underscores and be no more than X characters long.) In the worst case, this would make it easier to construct name-mangling algorithms for filesystems which have different rules. Oh yeah, one last thing: it would be really nice if io:fwrite("~p", [dotted.atom]) wouldn't add the unnecessary single quotes. But that's not a big deal. All in all it was nicer than I expected; I can live with it until something even better comes along. Just my 2c -Chris From cpressey@REDACTED Thu Sep 4 19:34:50 2003 From: cpressey@REDACTED (Chris Pressey) Date: Thu, 4 Sep 2003 10:34:50 -0700 Subject: Parameterised modules In-Reply-To: <3230-90099@sneakemail.com> References: <3230-90099@sneakemail.com> Message-ID: <20030904103450.0ed88586.cpressey@catseye.mine.nu> On 04 Sep 2003 11:37:08 +0200 "Lon Willett" wrote: > And while on the topic of parameterised modules, an issue that I am > concerned with is the handling of code change. I am not convinced > that the proposed handling is correct. I am not even sure what the > _right_thing_ is. As someone who didn't see the talk, forgive me if this is way off base. But I think I prefer a different approach. Although I forget exactly who mentioned it, I think it was one of the gurus who occasionally posts, during the last round of wish lists. Instead of parameterized modules, what about full-fledged lambda modules? Analogous to funs, I'll call them mods. Also analogous to funs I'll use the following syntax: Mod = mod function1(A1, A2) -> something. function2(A1, A2) -> something_else. end, This way you can 'parameterize' a module like so: String = "Hello, world!", Mod = mod print() -> io:fwrite("~s", [String]). end, Mod:print(). or, a better example might be printing_module(String) -> mod print() -> io:fwrite("~s", [String]). end. whatever() -> printing_module("Hello, world!"):print(). The thing is that these wouldn't be subject to code change (just like funs aren't.) Also, they might be able to be stored whole cloth in mnesia tables etc (again just like funs.) While these properties wouldn't make them suitable for everything (just like funs aren't,) I think they would be perfect for certain things (just like funs are.) They also strike me as much simpler than parameterized modules (from the programmer's point of view; I'm not really deeply considering how they'd have to be implemented.) Thoughts? -Chris From Zoltan.Toth@REDACTED Thu Sep 4 16:27:18 2003 From: Zoltan.Toth@REDACTED (Zoltan Peter Toth) Date: Thu, 04 Sep 2003 16:27:18 +0200 Subject: Supervisor, terminate_child Message-ID: <3F574BC6.9000200@eth.ericsson.se> Hi Erlang experts, I have a question about the supervisor behaviour of OTP: If I stop a child process of a supervisor instance 'manually', via supervisor:terminate_child(SupRef, Id) then is this checked against the restart frequency limit ? (i.e. does it count as a spontaneous exit, can it cause the supervisor to exit if done too frequently ?) Cheers, Zoltan From Erik.Stenman@REDACTED Thu Sep 4 18:12:41 2003 From: Erik.Stenman@REDACTED (Erik Stenman) Date: Thu, 4 Sep 2003 18:12:41 +0200 Subject: Packages in Erlang: new documentation Message-ID: Richard A. O'Keefe wrote: > Clearly I must have misunderstood *someone*, because to make > what I thought was proposed work, all you have to do is have > a local table of renamings in the module, and then have > apply/3 and spawn/3 and so on look in that table. The problem is that a local renaming is not enough. With the proposed scheme there can be two modules originally named foo, but one has been renamed to bar. How should a third module in the system doing apply(M,f,[]), with M bound to 'foo' know whether the atom refers to the module foo or the module bar? The atom 'foo' might have originated from the module renamed to bar and the intention might have been the module name foo, but you can not automatically just rename all occurrences of the atom 'foo' in the module to the atom 'bar'. The problem is that there is no "module-type" in Erlang, apply and spawn refers to modules by names. [...] > There are a number of things about that web page that bother me. > > > The first is that while the noun "package" is used often, > there doesn't seem to be any referent for it. There are > module objects, and there are name objects (the "case X of > foo.bar.baz ->" example suggests that dotted names are just > symbols). But there doesn't seem to be any *Erlang* object > for a "package" to refer to. Packages appear to have no > properties and enter into no relationships; there are really > only package *names*. More or less, just as there are only module *names* in Erlang today. > In short, from the inside, there appears to be no significant > difference between a module name like foo_bar_baz and a > module name like foo.bar.baz. The only difference is that from within the package foo.bar you can refer to foo.bar.baz as just baz, but the module foo_bar_baz has to be referred to with the hole name. You could also call packages module name spaces if it makes you less confused. > The second is that there is a fixed relationship between a > module name and a set of places to look for it. [... description of lots of problems cut out ...] Yes, but this is how modules work in Erlang today, it has not really anything to do with the new packages. All the problems you describe are already there in Erlang. The package extension is a suggestion for a backward compatible extension which will give you some addition advantages but it will not fix all problems that we have today. > Let me put this as bluntly as I possibly can: > While there may be a default mapping from Erlang module names > to files, it must be possible for someone installing a module > or package of modules to put each file exactly where s/he wants > without _any_ constraint on how files are named. It would probably be quite easy to rewrite the Erlang loader so that it looked in a user specified mapping from module names to file names. That is, there is really nothing that says that module names has to be mapped *directly* to filenames. But this is really an issue that is completely orthogonal to the package extension. /Erik -------------------------------------- I'm Happi, you should be happy. Praeterea censeo 0xCA scribere Erlang posse. -------------- next part -------------- A non-text attachment was scrubbed... Name: winmail.dat Type: application/ms-tnef Size: 3420 bytes Desc: not available URL: From enewhuis@REDACTED Thu Sep 4 20:27:58 2003 From: enewhuis@REDACTED (Eric Newhuis) Date: Thu, 04 Sep 2003 13:27:58 -0500 Subject: Supervisor, terminate_child In-Reply-To: <3F574BC6.9000200@eth.ericsson.se> References: <3F574BC6.9000200@eth.ericsson.se> Message-ID: <3F57842E.20309@futuresource.com> Hi, I must admit firstly that I don't have an answer to your question. Secondly, however, I am compelled to reveal to you that I think you have the most impressive looking and sounding name of anyone on the Erlang list. Cheers! Eric Newhuis From lennart.ohman@REDACTED Thu Sep 4 23:20:26 2003 From: lennart.ohman@REDACTED (=?ISO-8859-1?Q?Lennart_=D6hman?=) Date: Thu, 04 Sep 2003 23:20:26 +0200 Subject: Supervisor, terminate_child In-Reply-To: <3F574BC6.9000200@eth.ericsson.se> References: <3F574BC6.9000200@eth.ericsson.se> Message-ID: <3F57AC9A.7030208@st.se> Hi, The functions terminate_child, start_child, restart_child and delete_child were initially only meant as administrativ and for debugging purposes. However they have also become used for adding "dynamic" children after start-up of the supervisor. These functions do not count towards the restart intensity. To be precise. Only "illegal" terminations are counted towards the restart intensity. (The legallity is then determined by the permanence). Have fun! /Lennart Zoltan Peter Toth wrote: > Hi Erlang experts, > > I have a question about the supervisor behaviour of OTP: > > If I stop a child process of a supervisor instance 'manually', via > supervisor:terminate_child(SupRef, Id) > then is this checked against the restart frequency limit ? > (i.e. does it count as a spontaneous exit, can it cause the supervisor > to exit if > done too frequently ?) > > Cheers, > Zoltan > ------------------------------------------------------------- Lennart Ohman phone : +46-8-587 623 27 Sjoland & Thyselius Telecom AB cellular: +46-70-552 6735 Sehlstedtsgatan 6 fax : +46-8-667 8230 SE-115 28 STOCKHOLM, SWEDEN email : lennart.ohman@REDACTED From olgeni@REDACTED Fri Sep 5 00:25:21 2003 From: olgeni@REDACTED (Jimmy Olgeni) Date: Fri, 5 Sep 2003 00:25:21 +0200 (CEST) Subject: debugger-2.2 and online help In-Reply-To: <20030904164737.H38331@dev1.localdomain.net> References: <20030904164737.H38331@dev1.localdomain.net> Message-ID: <20030905001944.B234@olgeni.olgeni> Hi, I attached a small patch for the debugger help pathname issue. Unfortunately the open_help function expects to find netscape on any unix systems and nothing happens if it does not exist. I tried to fix that by looking at the BROWSER environment variable, then poking around for browser executable names that should support netscape's openURL command line protocol. -- jimmy -------------- next part -------------- $FreeBSD$ --- lib/debugger/src/dbg_ui_mon.erl.orig Thu Sep 4 22:26:08 2003 +++ lib/debugger/src/dbg_ui_mon.erl Thu Sep 4 22:26:51 2003 @@ -379,7 +379,7 @@ %% Help Menu gui_cmd('Debugger', State) -> - HelpFile = filename:join([code:lib_dir(debugger),"doc","index.html"]), + HelpFile = filename:join([code:lib_dir(debugger),"doc","html","index.html"]), tool_utils:open_help(State#state.gs, HelpFile), State; -------------- next part -------------- $FreeBSD$ --- lib/debugger/src/dbg_ui_trace.erl.orig Thu Sep 4 22:26:12 2003 +++ lib/debugger/src/dbg_ui_trace.erl Thu Sep 4 22:26:56 2003 @@ -352,7 +352,7 @@ %% Help menu gui_cmd('Debugger', State) -> - HelpFile = filename:join([code:lib_dir(debugger),"doc","index.html"]), + HelpFile = filename:join([code:lib_dir(debugger),"doc","html","index.html"]), tool_utils:open_help(State#state.gs, HelpFile), State; -------------- next part -------------- $FreeBSD$ --- lib/debugger/src/dbg_ui_view.erl.orig Thu Sep 4 22:26:16 2003 +++ lib/debugger/src/dbg_ui_view.erl Thu Sep 4 22:29:05 2003 @@ -165,7 +165,7 @@ %% Help menu gui_cmd('Debugger', State) -> - HelpFile = filename:join([code:lib_dir(debugger),"doc","index.html"]), + HelpFile = filename:join([code:lib_dir(debugger),"doc","html","index.html"]), tool_utils:open_help(State#state.gs, HelpFile), State. -------------- next part -------------- $FreeBSD$ --- lib/gs/src/tool_utils.erl.orig Thu Sep 4 23:01:37 2003 +++ lib/gs/src/tool_utils.erl Fri Sep 5 00:16:20 2003 @@ -27,6 +27,9 @@ -export([file_dialog/1]). -export([notify/2, confirm/2, confirm_yesno/2, request/2]). +%% Browser executable list (openURL command line protocol required) +-define(BROWSERS, ["netscape", "mozilla", "MozillaFirebird", "opera"]). + %%---------------------------------------------------------------------- %% open_help(GS, File) %% GS = gsobj() (GS root object returned by gs:start/0,1) @@ -51,7 +54,7 @@ local -> Cmd = case os:type() of {unix,_AnyType} -> - "netscape -remote \"openURL(file:" ++ File ++ ")\""; + unix_url_command("file:" ++ File); {win32,_AnyType} -> "start " ++ filename:nativename(File) @@ -62,7 +65,7 @@ remote -> Cmd = case os:type() of {unix,_AnyType} -> - "netscape -remote \"openURL(" ++ File ++ ")\""; + unix_url_command(File); {win32,_AnyType} -> "netscape.exe -h " ++ regexp:gsub(File,"\\\\","/") @@ -307,3 +310,54 @@ [Last]; insert_newlines(Other) -> Other. + +%% find_browser(BrowserList) => string() | false +%% BrowserList - [string()] +%% Given a list of basenames, find the first available executable. + +find_browser([]) -> + false; + +find_browser([H | T]) -> + case os:find_executable(H) of + false -> + find_browser(T); + Browser -> + Browser + end. + +%% unix_url_command(URL) => string() +%% URL - string() +%% Open an URL, using a browser which supports the openURL command +%% line protocol. If no browser is found, the empty string will be +%% returned. + +unix_url_command(URL) -> + Template = "BROWSER -remote \"openURL(" ++ URL ++ ")\" || BROWSER " ++ URL ++ "&", + + case os:getenv("BROWSER") of + false -> + %% look for a compatible browser + case find_browser(?BROWSERS) of + false -> + ""; + Browser -> + case regexp:gsub(Template, "BROWSER", Browser) of + {ok, Command, 0} -> + %% Template does not contain "BROWSER" placeholder + ""; + {ok, Command, _} -> + Command + end + end; + + Value -> + case regexp:gsub(Template, "BROWSER", Value) of + {ok, Command2, 0} -> + %% no placeholder + ""; + {ok, Command2, _} -> + Command2 + end + end. + From ok@REDACTED Fri Sep 5 01:59:37 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Fri, 5 Sep 2003 11:59:37 +1200 (NZST) Subject: Packages in Erlang: new documentation Message-ID: <200309042359.h84NxbSl337722@atlas.otago.ac.nz> "Vlad Dumitrescu" wrote: For the first, that would mean that every remote call will have to check first the internal module table for a rename. That would make these calls much slower. This is a bare assertion without any evidence to support it. With appropriate use of hash tables and caches, it could be _faster_. Again, if a module name is sent as a function argument, the local name wouldn't make sense to any other module. That is certainly a serious problem with the current proposal. One solution would be to extend the ?MODULE idea. ?MODULE ==> the full name of the current module + ?MODULE(local_name) ==> the full name of the module locally known as local_name. So instead of sending {foo,bar} to another module you'd send {?MODULE(foo),bar}. Sure, we could have a function to retrieve the complete name, but personally I feel it's more error-prone than elegant. Is there _any_ way of allowing abbreviations that is _not_ going to be error-prone? Finally, what about functional objects? The environment for a closure would need to include the rename table from the defining module. Not the _environment_. The parent module is simply part of the literal data for the code. >In short, from the inside, there appears to be no significant difference >between a module name like foo_bar_baz and a module name like foo.bar.baz. Only that locally you can use baz:fun(...) instead of the full module name. And THAT is the thing that creates all these difficulties. If baz:f(...) and (X = baz, X:f(...)) don't do the same thing, the language has serious semantic problems. If they _are_ to do the same thing, then either you don't have abbreviations, or you _have_ to look up module names in a per-module table somehow. And also that maybe one wants/needs to rename the 'foo' application, and then not all module names have to be updated. Please explain this more clearly with an example. The more I think about this, the clearer it seems that ANY kind of dotted module name scheme is a bad idea, and that something like the Eiffel approach is likely to be less trouble (more power, less complexity, less potential for error). From ok@REDACTED Fri Sep 5 03:05:39 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Fri, 5 Sep 2003 13:05:39 +1200 (NZST) Subject: Packages in Erlang: new documentation Message-ID: <200309050105.h8515diR342174@atlas.otago.ac.nz> I pointed out that apply/3 and spawn/3 and suchlike could be made to work in the presence of module renaming. This is a good time to point out that the longer I ponder this, and I have been thinking about Erlang modules for about 7 years now, the clearer it seems to me that (1) Module names must be completely decoupled from file names. [This does not mean that you cannot have a _default_ mapping from module names to file names, only that you cannot have a _fixed_ mapping.] (2) It is a bad idea to introduce names that don't actually name anything. Erlang modules are somewhat anomalous in the language. There really are module "objects", with many properties, but there are not module "values". If you don't believe that modules are objects in Erlang, take a look at the 'c' and 'code' modules, and you'll see what I mean. While you cannot ask a module *itself* for its properties, you can ask the Erlang system for the properties of a module. It is possible to have a system of hierarchical modules. That's how Pop-2 does it, and that's how Ada does it, and that's how Mercury does it. In those languages, modules may contain types, functions, _and other modules_. In contrast, this package proposal introduces a class of names that do not name anything. Where are the operations to - list all loaded packages - list all available packages - list the contents of a package - load a package - delete a package - purge a packge - ensure that a package is replicated on another node and so on? These operations may exist, but I didn't see them in the document we were asked to look at. If they do, I would be interested in reading a fuller version of the document. (3) Having packages that do not package is unhelpful. Java is notorious for this: packages are accessibility scopes, but anybody can sneak new classes and subpackages into a package without the package having any say about it. This is really a fundamental problem with Java packages, and the scheme under consideration is far too Java-like for my taste. If there are to be packages, then a package should be able to list its children and insist that no other purported children are legitimate. (4) A satisfactory solution to the "package" problem must deal with the issues of - including a module at more than one place in the space of packages - including more than one version of a module in a complete system If you consider these issues, you discover that the one thing that a module must NOT do is to know its exact place in a hierarchy of packages. (5) For large scale systems, the rules for binding modules together have to be outside the modules. For a long time SASL felt wrong to me: I thought most of the information in SASL files belonged in the modules. But then I studied LACE, and understood what problems the LACE design was trying to solve, and realised that I was wrong about where the information belonged. It's also worth looking at the configuration/distribution language that was developed for MESA. (6) Global name spaces are a pain for really large systems. The global process registry (ANY global process registry) is an idea whose time has gone. The global module registry (ANY global module registry, whether module names are simple or dotted) is also an idea whose time has gone. Yes, this means that apply/3 and spawn/3 and so on need rethinking. Now that Erlang has closures, there are alternatives... (7) JAM was not the last word in Erlang implementations. BEAM will not be the last word in Erlang implementations. "BEAM does so-and-so in such-and-such a manner" may decide what designs are easy to experiment with atop BEAM, but must not be allowed to dictate which designs are considered at all. "Vlad Dumitrescu" wrote: [about using a per-module renaming table] For the first, that would mean that every remote call will have to check first the internal module table for a rename. That would make these calls much slower. This is an assertion without any evidence to back it up. The experience of Smalltalk has, I believe, provided evidence that the assertion is untrue. Again, if a module name is sent as a function argument, the local name wouldn't make sense to any other module. This is definitely a problem with the existing scheme that we are discussing. The only way around it that does not introduce inconsistencies into the language is to ban module name abbreviation. Consider foo:bar() and (X = foo, X:bar()) and (X = foo, Y = bar, apply(X, Y, [])) where foo is the local abbreviation of ick.ack.uck.foo If these DON'T do the same thing, the language is inconsistent. If they DO do the same thing, then apply/3 _has_ to use a per-module renaming table somehow. Finally, what about functional objects? The environment for a closure would need to include the rename table from the defining module. I'm assuming standard terminology where "environment" refers to variable bindings and "code" refers to the static data (including literals). No, the module context for a closure would _not_ be part of its environment, it would be part of (the literals of) the code. Again, either you do this or you introduce inconsistency into the language. Consider foo:bar() and (fun () -> foo:bar() end)() If these DON'T do the same thing, the language is inconsistent. If they DO do the same thing, then closures have to know how to do the same renaming that the statically enclosing module would. I am not proposing any new kind of renaming. In these examples I am only referring to the kind of local abbreviation in the *existing* scheme. These problems are solvable, but look like are imposing more restrictions for the programmer than they remove. These problems *must* be solved if the *existing* scheme is not to result in an inconsistent language. The Simplest Thing That Could Possibly Work is to ban _all_ module renaming and abbreviation. >In short, from the inside, there appears to be no significant difference >between a module name like foo_bar_baz and a module name like foo.bar.baz. Only that locally you can use baz:fun(...) instead of the full module name. And we have now established that that kind of renaming EITHER yields an inconsistent language OR requires the kind of per-module renaming I mentioned before anyway. And also that maybe one wants/needs to rename the 'foo' application, and then not all module names have to be updated. Actually, this is one of my main concerns, and it is one of the most important reasons why I feel that ANY dotted name scheme is a bad idea. From cpressey@REDACTED Fri Sep 5 07:37:33 2003 From: cpressey@REDACTED (Chris Pressey) Date: Thu, 4 Sep 2003 22:37:33 -0700 Subject: Packages in Erlang: new documentation In-Reply-To: <200309050105.h8515diR342174@atlas.otago.ac.nz> References: <200309050105.h8515diR342174@atlas.otago.ac.nz> Message-ID: <20030904223733.2840ccf3.cpressey@catseye.mine.nu> On Fri, 5 Sep 2003 13:05:39 +1200 (NZST) "Richard A. O'Keefe" wrote: > I pointed out that apply/3 and spawn/3 and suchlike could be made > to work in the presence of module renaming. > > This is a good time to point out that the longer I ponder this, > and I have been thinking about Erlang modules for about 7 years now, > the clearer it seems to me that > > (1) Module names must be completely decoupled from file names. > [This does not mean that you cannot have a _default_ mapping > from module names to file names, only that you cannot have a > _fixed_ mapping.] OK, so consider the current mapping the default one, and consider the mechanism to change mappings, not yet implemented. As pointed out, it would not be hard to implement seamlessly. It just seems that no one has yet been put in a position to need to do it, yet. > (2) It is a bad idea to introduce names that don't actually name > anything. > > Erlang modules are somewhat anomalous in the language. There > really are module "objects", with many properties, but there are > not module"values". If you don't believe that modules are objects > in Erlang, take a look at the 'c' and 'code' modules, and you'll > see what I mean. While you cannot ask a module *itself* for its > properties, you can ask the Erlang system for the properties of a > module. If modules are objects in Erlang, then so are files and TCP/IP sockets. And packages. None of these are "first-class types", though; for example, you can't say 'f(X) when is_module(X).' All we really have are references to modules via their names (atoms.) Ditto packages. > It is possible to have a system of hierarchical modules. That's > how Pop-2 does it, and that's how Ada does it, and that's how > Mercury does it. In those languages, modules may contain types, > functions,_and other modules_. > > In contrast, this package proposal introduces a class of names > that do not name anything. Where are the operations to > - list all loaded packages > - list all available packages > - list the contents of a package > - load a package > - delete a package > - purge a packge > - ensure that a package is replicated on another node > and so on? Again, just consider them not yet implemented. They'd be trivial to implement (e.g. listing the contents of a package would be implemented in terms of listing directory contents.) > These operations may exist, but I didn't see them in the document > we were asked to look at. If they do, I would be interested in > reading a fuller version of the document. I think you are building a straw man here. It's clear to me that package names *do* name something (they name namespaces, which are implemented with directories) and that there *are* operations which apply to them (even if they haven't been implemented yet.) > (3) Having packages that do not package is unhelpful. > > Java is notorious for this: packages are accessibility scopes, > but anybody can sneak new classes and subpackages into a package > without the package having any say about it. > > This is really a fundamental problem with Java packages, and the > scheme under consideration is far too Java-like for my taste. > > If there are to be packages, then a package should be able to list > its children and insist that no other purported children are > legitimate. Why? I mean, you obviously feel strongly about this, but you haven't explained why it's a problem. You're doing something similar to what you accused Vlad of, a message or two back: making an assertion that X is a bad thing without providing any evidence or reasoning for why it is bad. I guess I have a different notion of an 'accessibility scope', too - packages aren't about restricting what can and cannot be a 'child' of whatever else, so much as they're about: a) organizing modules to make them easier to locate, and b) reducing name clashes. > (4) A satisfactory solution to the "package" problem must deal with > the > issues of > - including a module at more than one place in the space of > packages- including more than one version of a module in a > complete system If you consider these issues, you discover that > the one thing that a module must NOT do is to know its exact place > in a hierarchy of packages. I think this problem only shows up when the code path is eliminated. For the sake of backwards-compatibility, it might never be. > (5) For large scale systems, the rules for binding modules together > have to be outside the modules. > > For a long time SASL felt wrong to me: I thought most of the > information in SASL files belonged in the modules. But then I > studied LACE, and understood what problems the LACE design was > trying to solve, and realised that I was wrong about where the > information belonged. It's also worth looking at the > configuration/distribution language that was developed for MESA. Doesn't this completely contradict the idea of hierarchical modules, where a module 'contains' other modules, then? If the hierarchical relationships between modules should be *outside* the modules, that would seem to be an argument for packages as something *distinct* from modules. > (6) Global name spaces are a pain for really large systems. > The global process registry (ANY global process registry) is > an idea whose time has gone. > The global module registry (ANY global module registry, whether > module names are simple or dotted) is also an idea whose time > has gone. Namespaces aren't registries. To me, a namespace is conceptual. And speaking conceptually, the top level of a hierarchy is ALWAYS global. How can it be anything but? Also, the set of fully-qualified names in a hierarchy is always isomorphic to a single namespace. That is, if I have a hierarchy like a +-a +-a +-b +-b +-a +-b ...it maps perfectly to a flat global list like a a.a a.a.a a.a.b a.b a.b.a a.b.b On the other hand, registries are implementations of the namespace concept. If you're saying that each process(/module/whichever) should only ever register its name with its immediate parent - well that would be good design a la the Law of Demeter, but it could also have performance consequences as name lookups become recursive. I think the ultimate decision for where the registries should be partitioned should be up to the engineer for any given project. The fact remains that conceptually, names can always be regarded as global in some sense. > Yes, this means that apply/3 and spawn/3 and so on need > rethinking. Now that Erlang has closures, there are > alternatives... Well, closures don't cut it if you want to support code change. > (7) JAM was not the last word in Erlang implementations. > BEAM will not be the last word in Erlang implementations. > "BEAM does so-and-so in such-and-such a manner" may decide what > designs are easy to experiment with atop BEAM, but must not be > allowed to dictate which designs are considered at all. Absolutely. Luckily, I know nothing about the innards of BEAM so you don't have to worry about my responses being influenced by it. > [...] > These problems *must* be solved if the *existing* scheme is not to > result in an inconsistent language. The Simplest Thing That Could > Possibly Work is to ban _all_ module renaming and abbreviation. Why the heck not just use a macro??? -define(foo, ick.ack.uck.foo). ... X = ?foo, X:bar(). -Chris From vlad_dumitrescu@REDACTED Fri Sep 5 09:19:31 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Fri, 5 Sep 2003 09:19:31 +0200 Subject: Packages in Erlang: new documentation References: <200309042359.h84NxbSl337722@atlas.otago.ac.nz> Message-ID: Hi, From: "Richard A. O'Keefe" >> For the first, that would mean that every remote call will have >> to check first the internal module table for a rename. That >> would make these calls much slower. > > This is a bare assertion without any evidence to support it. > With appropriate use of hash tables and caches, it could be _faster_. Erm, no... We are comparing a remote function call with a remote function call _plus_ a lookup - the latter can never be faster than the former, right? >> Again, if a module name is sent as a function argument, the >> local name wouldn't make sense to any other module. > > That is certainly a serious problem with the current proposal. > One solution would be to extend the ?MODULE idea. > So instead of sending {foo,bar} to another module you'd send > {?MODULE(foo),bar}. Yes, could work. Chris' suggestion of using a macro for each renamed module is even better, as it completely removes the lookup. > Is there _any_ way of allowing abbreviations that is _not_ going to be > error-prone? No, not really. But the benefits might overweigh the disadvantages, so the overall effect might be positive. >> Finally, what about functional objects? The environment for a closure would need >> to include the rename table from the defining module. > Not the _environment_. The parent module is simply part of the literal > data for the code. No, a static reference to the module is not good enough. Imagine a module defining a fun and at a later moment the module's code is being upgraded - and the name mapping changes! That would probably make the original fun crash in an obscure way. I agree, this is no good programming practice, but if something can happen, it wil lhappen sooner or later. > If baz:f(...) and (X = baz, X:f(...)) don't do the same thing, > the language has serious semantic problems. > If they _are_ to do the same thing, then either you don't have > abbreviations, or you _have_ to look up module names in a per-module > table somehow. Hmm, good point. Maybe Richard Carlsson can comment on this. Is the module abbreviation going to work with variables as module names, or only at compile-time? >> And also that maybe one wants/needs to rename the 'foo' >> application, and then not all module names have to be updated. > Please explain this more clearly with an example. I meant that if I write an application named foofoo, and later have to rename it to barbar, then today I have to rename all foofoo_something modules and the references to them, both from inside tha application and from its clients. With the proposed scheme, only references from the outside need to be changed. It's not really a big problem, I agree. > The more I think about this, the clearer it seems that ANY kind of > dotted module name scheme is a bad idea, and that something like > the Eiffel approach is likely to be less trouble (more power, less > complexity, less potential for error). Maybe, maybe not. This is what we try to find out :-) I just wanted to point out that no solution is perfect, and thus we have to try to find one that fits best with what we need most. best regards, Vlad From vlad_dumitrescu@REDACTED Fri Sep 5 09:28:51 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Fri, 5 Sep 2003 09:28:51 +0200 Subject: Packages in Erlang: new documentation References: <200309050105.h8515diR342174@atlas.otago.ac.nz> <20030904223733.2840ccf3.cpressey@catseye.mine.nu> Message-ID: Hi, >From: "Chris Pressey" > Why the heck not just use a macro??? > > -define(foo, ick.ack.uck.foo). > ... > X = ?foo, X:bar(). A very simple and straightforward idea, I think! A question: should it be -define(foo, ick.ack.uck.foo). or -define(foo, 'ick.ack.uck.foo').? Seems to me that only in a call context it works without quotes, or maybe I didn't RTFM :) >"Richard A. O'Keefe" wrote: >> (1) Module names must be completely decoupled from file names. >> [This does not mean that you cannot have a _default_ mapping >> from module names to file names, only that you cannot have a >> _fixed_ mapping.] As a matter of fact, there is an alternate code loader, where module are not being mapped to files: Joe's SAE. All modules are tar'ed (or similar) and are part of the executable. best regards, Vlad From joachim.durchholz@REDACTED Fri Sep 5 09:53:08 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Fri, 05 Sep 2003 09:53:08 +0200 Subject: Packages in Erlang: new documentation In-Reply-To: <200309050105.h8515diR342174@atlas.otago.ac.nz> References: <200309050105.h8515diR342174@atlas.otago.ac.nz> Message-ID: <3F5840E4.3020000@web.de> Richard A. O'Keefe wrote: > I pointed out that apply/3 and spawn/3 and suchlike could be made > to work in the presence of module renaming. > > This is a good time to point out that the longer I ponder this, > and I have been thinking about Erlang modules for about 7 years now, > the clearer it seems to me that > > (1) Module names must be completely decoupled from file names. > [This does not mean that you cannot have a _default_ mapping > from module names to file names, only that you cannot have a > _fixed_ mapping.] I agree that the names should be decoupled to allow people to organize the files on their disk. I disagree in that the flexibility should not be limitless. In particular, my ideal would be that a human would need no more than a single lookup to determine where to find any set of modules. (Think situations like: a consultant is trying to make sense of the file organisation of a customer.) > It is possible to have a system of hierarchical modules. That's > how Pop-2 does it, and that's how Ada does it, and that's how Mercury > does it. In those languages, modules may contain types, functions, > _and other modules_. Minor point: I'm not sure that nested modules gain much. > (3) Having packages that do not package is unhelpful. > > Java is notorious for this: packages are accessibility scopes, > but anybody can sneak new classes and subpackages into a package > without the package having any say about it. > > This is really a fundamental problem with Java packages, and the > scheme under consideration is far too Java-like for my taste. > > If there are to be packages, then a package should be able to list > its children and insist that no other purported children are legitimate. This is a problem because classes in the same package have additional privileges. If "being in the same package" doesn't give a module any additional privileges, there's no point in doing so and the problem disappears. (I haven't looked too deeply into the Erlang package proposal, so I'm not sure how the situation here is. I'm just pointing out that there are more design alternatives than have been made out.) When weighing the alternatives, I see that closing the packages means that programmers have to write manifestos. That's redundant information, with all the associated problems. > (4) A satisfactory solution to the "package" problem must deal with the > issues of > - including a module at more than one place in the space of packages I'm not sure how this becomes relevant? > - including more than one version of a module in a complete system This is most definitely relevant. The Unix solution (simply include version numbers in the module names) seems to work best. > If you consider these issues, you discover that the one thing that > a module must NOT do is to know its exact place in a hierarchy of > packages. Again, I think the design space is larger than presented. > (7) JAM was not the last word in Erlang implementations. > BEAM will not be the last word in Erlang implementations. > "BEAM does so-and-so in such-and-such a manner" may decide what > designs are easy to experiment with atop BEAM, but must not be > allowed to dictate which designs are considered at all. Agreed - modulo the constraint that the time of the Erlang team is limited. In other words: design alternatives should be discussed even if they go beyond current BEAM mechanisms, but BEAM compatibility should definitely be a factor when deciding which mechanism to implement. Regards, Jo From vlad_dumitrescu@REDACTED Fri Sep 5 09:56:33 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Fri, 5 Sep 2003 09:56:33 +0200 Subject: Packages in Erlang: new documentation References: <200309050105.h8515diR342174@atlas.otago.ac.nz> Message-ID: From: "Richard A. O'Keefe" > (1) Module names must be completely decoupled from file names. > [This does not mean that you cannot have a _default_ mapping > from module names to file names, only that you cannot have a > _fixed_ mapping.] I am wondering... Some kind of mapping to files must exist, because one has to be able to track down errors and crashes to their source code. And this mapping should not rely on a running Erlang system, because in case of a hardware failure it might be impossible to get one up. Hmm, as it just dawned on me, there are really two different mappings: module <-> location of beam code and module <-> source code file. The former is interesting for the code loader, and the location could be a file per beam, or one common file for all beams, or an URI, or something else. Any one of these can be implemented transparently, so it's not really a big deal. The latter is useful for us developers, and I believe is discussed here - isn't it? As I understand the package proposal, it is meant to help with the mapping to source code, while inside the beam vm the namespace is still flat, only the module names happen to have dots inside them. Is this correct? (question aimed at Richard Carlsson) If it is, maybe not all our comments are relevant for the moment, like for example "packages not packaging anything" is a runtime issue, not source code related. best regards, Vlad From ulf.wiger@REDACTED Fri Sep 5 12:49:35 2003 From: ulf.wiger@REDACTED (=?ISO-8859-1?Q?Ulf_Wiger_=28=C4L2/EAB=29?=) Date: Fri, 5 Sep 2003 12:49:35 +0200 Subject: nocatch in erl_compile Message-ID: <76E5F712842F5F49A35738622BAA0F4F9EA6F4@ESEALNT442.al.sw.ericsson.se> A small typo when using erlc revealed a bug (both OTP R9B and R9C): []: erlc +P env_jit.erl bad term: P Runtime error: {{nocatch,error}, [{erl_compile,make_term,1}, {erl_compile,compile1,3}, {erl_compile,compiler_runner,1}]} /Uffe From richardc@REDACTED Fri Sep 5 18:38:05 2003 From: richardc@REDACTED (Richard Carlsson) Date: Fri, 5 Sep 2003 18:38:05 +0200 (MET DST) Subject: Parameterised modules In-Reply-To: <20030904103450.0ed88586.cpressey@catseye.mine.nu> References: <3230-90099@sneakemail.com> <20030904103450.0ed88586.cpressey@catseye.mine.nu> Message-ID: On Thu, 4 Sep 2003, Chris Pressey wrote: > Instead of parameterized modules, what about full-fledged lambda > modules? > > Analogous to funs, I'll call them mods. Also analogous to funs I'll use > the following syntax: > > Mod = mod > function1(A1, A2) -> something. > function2(A1, A2) -> something_else. > end, > > This way you can 'parameterize' a module like so: > > String = "Hello, world!", > Mod = mod > print() -> io:fwrite("~s", [String]). > end, > Mod:print(). I have considered this, but the implementation issues are very hairy indeed, when you have to think about things like code updates (if the result _is_ a module, then calling it should not have different semantics from calling any other module - right?), and distributed Erlang. Java introduced such a thing in 1.1 - they call it "anonymous classes", in analogy with "anonymous functions" (lambdas). They are often used for writing small, one-shot callback objects such as listeners. They implement them by letting the compiler autogenerate names like "Foo$3" (for the third anonymous class in class "Foo"), so you get extra object files "Foo$3.class", etc. But you don't do a lot of dynamic code update in Java, and it seems that they are not worried about the fact that if two "nodes" are running the same code initially, but one gets a bug fix that causes the numbering of these "anonymous" classes to change, the whole thing could go down. I've been thinking a lot about the problems with "anonymous things", code update and distribution, but I don't have any good answers yet. That's mainly why I did not mention the possibility of "anonymous modules" in my workshop presentation. /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ "Having users is like optimization: the wise course is to delay it." -- Paul Graham From M.A.M@REDACTED Sat Sep 6 22:58:34 2003 From: M.A.M@REDACTED (Michael Mayr) Date: Sat, 6 Sep 2003 22:58:34 +0200 Subject: Interesting for wrapper project? Forward: Guis 1.4 release (GTK2 scriptable widget server) Message-ID: <200309062058.h86KwYQ12169@mailgate5.cinetic.de> **** This is a forward because something similar has been suggested a few days ago in the "The wrapper project" thread and I thought it might be of interest to someone on this list. Please forgive me if I'm wrong. I am not the original announcer and have no connection to him. **** **** start of citation from comp.lang.python **** Dear All, This is to announce availability of Guis-1.4 (opensource under GPL) Guis widget server is a Gtk2 widget server. It listens on pipes for widget requests (in the Python or Ruby scripting languages), and emit replies or events in textual lines (e.g. Lispy, XML or plain token syntax). Actually, there are 2 different programs: ruguis is Guis for Ruby and pyguis is Guis for Python, sharing some common source code. See http://freshmeat.net/projects/guis/ and http://www.starynkevitch.net/Basile/guisdoc.html and download http://www.starynkevitch.net/Basile/guis-1.4.tar.gz a 518832 byte gnuzipped source tarball of md5sum 5b5e5666a0b878adb170c626b44b5f87 Guis uses the PyGTK binding for Python to GTK2 and the ruby-gnome2 binding for Ruby to GTK2. Changlog since 1.3 * bug fixes, notably fixed coredump when shrinking read buffer * trace window use char wrap * logfile ability * support for Python2.2 & 2.3 and for Ruby1.8 * better support for gtk main loop inside & outside initial script I'm CC-ing the PyGTK and rubygnome2 mailing lists I'll be delighted by feedback! -- Basile STARYNKEVITCH http://starynkevitch.net/Basile/ email: basilestarynkevitchnet aliases: basiletunesorg = bstarynknerimnet 8, rue de la Fa?encerie, 92340 Bourg La Reine, France **** end of citation from comp.lang.python **** Greetings Michael. ______________________________________________________________________________ 38xTestsieger - WEB.DE FreeMail - Deutschlands beste E-Mail! Kommunizieren Sie sicher und ganz privat- http://f.web.de/?mc=021134 From james@REDACTED Mon Sep 8 00:43:45 2003 From: james@REDACTED (James Hague) Date: Sun, 7 Sep 2003 17:43:45 -0500 Subject: BEAM documentation (was Re: Packages in Erlang...) Message-ID: <3F5B6E51.16454.289DB0@localhost> Richard A. O'Keefe wrote: >(7) JAM was not the last word in Erlang implementations. > BEAM will not be the last word in Erlang implementations. > "BEAM does so-and-so in such-and-such a manner" may decide what > designs are easy to experiment with atop BEAM, but must not be > allowed to dictate which designs are considered at all. That's a good point, and it is worth emphasizing. Statements to the effect of "BEAM doesn't that allow that," while not frequent, have come up enough that my attention is drawn to them (see the "Tail Recursion" thread for another example. What worries me is that the workings of the BEAM emulator are essentially undocumented--and there don't appear to be any plans to document them--which makes the emulator much more opaque than it should be, and yet the Erlang language is fundamentally reliant on it. Certainly there should be a successor to BEAM at some point, one that's not so wrapped up in historical decisions, or at least alternative implementations of BEAM. This could be handled by someone outside of Ericsson, were the architecture of emulator less of a mystery. (One idea I've mused about is doing away with the C implementation of the BEAM emulator entirely, and writing the core in a custom mid- level language implemented in Erlang.) From Bengt.Kleberg@REDACTED Mon Sep 8 09:19:26 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Mon, 08 Sep 2003 09:19:26 +0200 Subject: Packages in Erlang: new documentation In-Reply-To: References: Message-ID: <3F5C2D7E.7040408@ericsson.com> Richard Carlsson wrote: > ...deleted > stuffed with hundreds of files with very long names. it is (arguably, but imho :-) better to have _one_ /bin directory with all files, than several /bin, /sbin, /usr/bin, /usr/sbin, ... (the company default $path have > 20 entries, to which i add 2). i think the same goes for the erlang load path. > I agree that search > paths are evil. The Erlang/OTP default search path contains about 45 > entries! And yet all of these are subdirectories of the "lib" directory. > With packages, it could be just a single entry in the path. this is the 'good thing'' about packages. one entry in the load path, and then the name tells me where to look. bengt From Bengt.Kleberg@REDACTED Mon Sep 8 09:30:51 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Mon, 08 Sep 2003 09:30:51 +0200 Subject: free_vars/1 In-Reply-To: References: <76E5F712842F5F49A35738622BAA0F4F9EA6F0@ESEALNT442.al.sw.ericsson.se> <3F5733C3.3030401@ericsson.com> Message-ID: <3F5C302B.2000904@ericsson.com> Luke Gorrie wrote: ...deleted > > Are you doing this via Distel? (Distel has a command to automate this > refactoring.) i still have not learned emacs, so i do not use distel. > This is taken care of in the CVS version of Distel. My solution was to > remove all the macros with some Elisp code before sending it to Erlang > and Richard's analysis program. Specifically, "?ANYTHING" becomes > "deadmacro". (It's okay to mutilate the code arbitrarily so long as > the set of free variables is preserved.) i am using free_vars as a ''black box''. (ok, so i change things inside it, and it is not a real black box. but i do not know how it works, honestly :-) if it is ''okay to mutilate the code arbitrarily'' why not just remove the macro? ...deleted > > (Thanks to Tobbe T?rnkvist for using the refactoring feature enough to > motivate the fix :-) > thank you for the free_vars function. i deal with loads of code that need refactoring all the time, and it helps a lot. bengt From Bengt.Kleberg@REDACTED Mon Sep 8 10:08:53 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Mon, 08 Sep 2003 10:08:53 +0200 Subject: free_vars/1 In-Reply-To: References: <76E5F712842F5F49A35738622BAA0F4F9EA6F0@ESEALNT442.al.sw.ericsson.se> <3F5733C3.3030401@ericsson.com> Message-ID: <3F5C3915.60902@ericsson.com> Richard Carlsson wrote: ...deleted > If you take a look at the module 'epp_dodger.erl' in the syntax_tools > contribution, it does a similar trick to get code containing macros past > the parser. (It handles most "sane" uses of macros.) You might be able > to use it directly, or just steal some parts of the code. > thank you for the help. epp_dodger has some well thought out functions (unexported, but that is easily handled). unfortunatly the most lowlevel ones (scan_macro/1 and scan_form/1) gives the unwanted result of turning the macro into a free variable. input lines: case catch free_vars(Lines) of {error, Reason} -> io:format( "CRASH ~w: ~s~n", [?MODULE, Reason] ); Free -> Function_head = function_head( Free ), io:put_chars(lists:append( Function_head, Lines )) end, result: (MODULE,Lines) -> the more high level ones (parse_tokens/1 and rewrite_form/1) crash: {"init terminating in do_boot",{put_chars,[{io,format,[<0.19.0>,"CRASH ~w: ~s~n",[erlrefactor,{1,erl_parse,["syntax error before: ",["'case'"]]}]]},{erlrefactor,main,1},{init,start_it,1},{init,start_em,1}]}} i will (try to) keep epp_dodger in mind when my macros_to_atoms/1 starts to fail me. bengt From joe@REDACTED Mon Sep 8 10:12:05 2003 From: joe@REDACTED (Joe Armstrong) Date: Mon, 8 Sep 2003 10:12:05 +0200 (CEST) Subject: Old Erlang version Message-ID: Hello, Does anybody have an old Erlang version lying around? I seem to have lost my old Erlang's I'd like an *old* version of Erlang - preferably the last version where the JAM compiler worked correctly and could bootstrap itself. I'm not sure of the version number. (I tried the earliest version in the otp download/old directory erlang_base-47.4.1.src.tar.gz but this seems buggy - for example making a parser from erl_parse.yrl makes a parser which will do compile correctly) So I guess I either want an earlier version - Or a later version that compiles correctly. What I'd really like was the last version that had both the beam and the jam where the jam worked and the beam was experimental - just before the default machine was changed to the beam - I don't even know which version this was ... If anybody knows where I could get hold of this I'd be very grateful Thanks a lot /Joe From vlad_dumitrescu@REDACTED Mon Sep 8 10:23:39 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Mon, 8 Sep 2003 10:23:39 +0200 Subject: BEAM documentation (was Re: Packages in Erlang...) References: <3F5B6E51.16454.289DB0@localhost> Message-ID: Hi, From: "James Hague" > (One idea I've mused about is doing away with the C implementation of > the BEAM emulator entirely, and writing the core in a custom mid- > level language implemented in Erlang.) That would be interesting, but you still need something running the Erlang code that runs the new BEAM VM? Or does the bootstrapping trick work in this case too? Doesn't one need machine code generation for that? (I mean an interpreted VM engine would probably be too slow for industrial use - but it might be a very useful learning tool). best regards, Vlad From richardc@REDACTED Mon Sep 8 10:52:35 2003 From: richardc@REDACTED (Richard Carlsson) Date: Mon, 8 Sep 2003 10:52:35 +0200 (MET DST) Subject: free_vars/1 In-Reply-To: <3F5C3915.60902@ericsson.com> References: <76E5F712842F5F49A35738622BAA0F4F9EA6F0@ESEALNT442.al.sw.ericsson.se> <3F5733C3.3030401@ericsson.com> <3F5C3915.60902@ericsson.com> Message-ID: On Mon, 8 Sep 2003, Bengt Kleberg wrote: > epp_dodger has some well thought out functions (unexported, but that > is easily handled). Perhaps I should have a look and see what other functions could be useful if exported. > unfortunatly the most lowlevel ones (scan_macro/1 and scan_form/1) > gives the unwanted result of turning the macro into a free variable. > > input lines: > case catch free_vars(Lines) of > {error, Reason} -> > io:format( "CRASH ~w: ~s~n", [?MODULE, Reason] ); > Free -> > Function_head = function_head( Free ), > io:put_chars(lists:append( Function_head, Lines )) > end, Lexically, macro names can be both atoms and variables, so you'd need to encode this in some way that hides such variables from the 'free_vars' function. I didn't do that. > the more high level ones (parse_tokens/1 and rewrite_form/1) crash: Yes, they expect full "forms" (like function definitions and attributes), not just any expression. /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ "Having users is like optimization: the wise course is to delay it." -- Paul Graham From joe@REDACTED Mon Sep 8 14:18:57 2003 From: joe@REDACTED (Joe Armstrong) Date: Mon, 8 Sep 2003 14:18:57 +0200 (CEST) Subject: Wither Self Message-ID: Shouldn't there be a Self in funs? IMHO writing: Fac = fun(0) -> 1; (N) -> N*Self(N-1) end is just teensy weensy bit simpler than: Fact = fun(X) -> G = fun(0, F) -> 1; (N, F) -> N*F(N-1,F) end, G(X, G) end. I don't really know my way around the code base since it's been reorganised - it should be just a quick hack in the linter and lambda lifter - but what these are called today I have no idea :-) /Joe From rpettit@REDACTED Mon Sep 8 16:00:08 2003 From: rpettit@REDACTED (Rick Pettit) Date: Mon, 8 Sep 2003 07:00:08 -0700 Subject: Old Erlang version In-Reply-To: References: Message-ID: <20030908140008.GA31067@vailsys.com> On Mon, Sep 08, 2003 at 10:12:05AM +0200, Joe Armstrong wrote: > > Hello, > > Does anybody have an old Erlang version lying around? > > I'd like an *old* version of Erlang - preferably the last version > where the JAM compiler worked correctly and could bootstrap itself. > > I'm not sure of the version number. > > (I tried the earliest version in the otp download/old directory > erlang_base-47.4.1.src.tar.gz but this seems buggy - for example > making a parser from erl_parse.yrl makes a parser which will do > compile correctly) > > So I guess I either want an earlier version - Or a later version > that compiles correctly. Well, OpenBSD to this day still ships with erlang_base-47.4.0 in the ports collection. It has been quite a while since I built the port (just grab the source, patch, and build that for current goodies), but last time I tried it compiled and seemed to work just fine. You can probably find it as a built package on some OpenBSD CD (I can check mine when I get home tonight). Of course the source itself comes straight from the erlang site (unless it has been removed). Hope that helps. -Rick From joachim.durchholz@REDACTED Mon Sep 8 15:36:32 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Mon, 08 Sep 2003 15:36:32 +0200 Subject: Wither Self In-Reply-To: References: Message-ID: <3F5C85E0.6030306@web.de> Joe Armstrong wrote: > > Shouldn't there be a Self in funs? > > IMHO writing: > > Fac = fun(0) -> 1; > (N) -> N*Self(N-1) end > > is just teensy weensy bit simpler than: > > Fact = fun(X) -> > G = fun(0, F) -> 1; > (N, F) -> N*F(N-1,F) > end, > G(X, G) > end. That's nice, but it doesn't handle mutual recursion. Personally, I'd prefer a scope construct that first introduces a set of names, then binds definitions to them. Syntactically, this need not have an ugly syntax; I'm thinking along lines like these: define Fac = fun/1 0 -> 1; N -> N * Fac (N - 1) end some_constant = 2; Even = fun/1 0 -> True; N -> odd (N - 1) end Odd = fun/1 1 -> False; N -> Even (N - 1) end end (I know this is very different from the current fun syntax, more a "how I'd like it if I could designed it scratch" thing.) Just my 2c. Regards, Jo From jamesh@REDACTED Mon Sep 8 15:39:35 2003 From: jamesh@REDACTED (James Hague) Date: Mon, 8 Sep 2003 08:39:35 -0500 Subject: BEAM documentation (was Re: Packages in Erlang...) Message-ID: Vlad Dumitrescu wrote: >That would be interesting, but you still need >something running the Erlang code that runs >the new BEAM VM? Or does the bootstrapping >trick work in this case too? Doesn't one >need machine code generation for that? Yes, it would need to generate machine code as a final step. The more I think about it, the more similarities I see between implementing a Forth compiler and the BEAM emulator. I'm not talking about RPN and such--BEAM is register based--but how relatively easy it is to generate code when you are specializing it for a particular abstract machine and not a full-fledged C-like language. An equally interesting project would be be to write a BEAM emulator using one of the modern, machine code generating Forths that have become standard (here's an example: http://www.mpeltd.demon.co.uk/pfwvfx.htm). Essentially the main loop of the emulator, the one that's reliant on the gcc "address of label" extension, is how a Forth with tail-call support works. For these paths to be opened up, I'd like to see two things happen: 1. Decent documentation of the BEAM architecture and instruction set. 2. Move most of the code from the "beam_load.c" module to the Erlang compiler. This is the module that replaces generic BEAM instructions with specialized instructions. This code would be much cleaner in Erlang than in C, and it would also simplify the emulator (beam_load.c is the second largest module in the emulator). From tony@REDACTED Mon Sep 8 16:19:10 2003 From: tony@REDACTED (Tony Rogvall) Date: 08 Sep 2003 16:19:10 +0200 Subject: Erlang on XBOX Message-ID: <1063030748.2004.8.camel@localhost.localdomain> Add an other platform to the Erlang port list :-) root@REDACTED:~# root@REDACTED:~# uname -a Linux xbox.localdomain.local 2.4.21-xbox #1 Mon Jul 14 11:12:49 UTC 2003 i686 unknown root@REDACTED:~# erl Erlang (BEAM) emulator version 5.3 [source] [hipe] [threads:0] Eshell V5.3 (abort with ^G) 1> /Tony From Marc.Vanwoerkom@REDACTED Mon Sep 8 16:46:12 2003 From: Marc.Vanwoerkom@REDACTED (Marc Ernst Eddy van Woerkom) Date: Mon, 8 Sep 2003 16:46:12 +0200 (MEST) Subject: Erlang on XBOX In-Reply-To: <1063030748.2004.8.camel@localhost.localdomain> (message from Tony Rogvall on 08 Sep 2003 16:19:10 +0200) Message-ID: <200309081446.h88EkCH03976@bonsai.fernuni-hagen.de> > root@REDACTED:~# uname -a > Linux xbox.localdomain.local 2.4.21-xbox #1 Mon Jul 14 11:12:49 UTC 2003 > root@REDACTED:~# erl > Erlang (BEAM) emulator version 5.3 [source] [hipe] [threads:0] Cool. What do I need - an XBox, some game with weakness, a network card? And does this still beat cheap new PCs? Regards, Marc From svg@REDACTED Mon Sep 8 16:29:46 2003 From: svg@REDACTED (Vladimir Sekissov) Date: Mon, 08 Sep 2003 20:29:46 +0600 (YEKST) Subject: Wither Self In-Reply-To: References: Message-ID: <20030908.202946.39097953.svg@surnet.ru> Good day, joe> joe> joe> Shouldn't there be a Self in funs? joe> joe> IMHO writing: joe> joe> Fac = fun(0) -> 1; joe> (N) -> N*Self(N-1) end joe> joe> is just teensy weensy bit simpler than: joe> joe> Fact = fun(X) -> joe> G = fun(0, F) -> 1; joe> (N, F) -> N*F(N-1,F) joe> end, joe> G(X, G) joe> end. It would be very nice. For now this natural from user point of view code could be down only with some tricks: -define(lambda(Name, Arg, Body), y(fun (Name) -> fun Arg -> Body end end)). y(X) -> F = fun (P) -> X(fun (Arg) -> (P(P))(Arg) end) end, F(F). test() -> Fact = ?lambda(Fact, (N), if (N == 0) -> 1; true -> N * Fact(N-1) end ). Best Regards, Vladimir Sekissov From Zoltan.Toth@REDACTED Mon Sep 8 15:59:59 2003 From: Zoltan.Toth@REDACTED (Zoltan Peter Toth) Date: Mon, 08 Sep 2003 15:59:59 +0200 Subject: Shared heap in R9C-0 ? Message-ID: <3F5C8B5F.90700@eth.ericsson.se> Hi, A question mainly to Erlang developers: In the source README file for R9B the --enable-shared-heap configure option was explicitely mentioned. In R9C-0 it is not mentioned, but it still works. So when starting the erlang machine built like this, it prints Erlang (BEAM) emulator version 5.3 [source] [hipe] [shared heap] [threads:0] ^^^^^^^^^^^^^ According to some measurements I made, it really provides some speedup. So my question is: Why is it not mentioned in the configure help or the README file ? Is it planned to be removed ? Is it not considered stable ? Best regards, Zoltan From joe@REDACTED Mon Sep 8 19:00:37 2003 From: joe@REDACTED (Joe Armstrong) Date: Mon, 8 Sep 2003 19:00:37 +0200 (CEST) Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: Message-ID: On Mon, 8 Sep 2003, James Hague wrote: > Vlad Dumitrescu wrote: > >That would be interesting, but you still need > >something running the Erlang code that runs > >the new BEAM VM? Or does the bootstrapping > >trick work in this case too? Doesn't one > >need machine code generation for that? > > Yes, it would need to generate machine code as a final step. The more I > think about it, the more similarities I see between implementing a Forth > compiler and the BEAM emulator. I'm not talking about RPN and such--BEAM is > register based--but how relatively easy it is to generate code when you are > specializing it for a particular abstract machine and not a full-fledged > C-like language. > > An equally interesting project would be be to write a BEAM emulator using > one of the modern, machine code generating Forths that have become standard > (here's an example: http://www.mpeltd.demon.co.uk/pfwvfx.htm). Essentially > the main loop of the emulator, the one that's reliant on the gcc "address of > label" extension, is how a Forth with tail-call support works. > > For these paths to be opened up, I'd like to see two things happen: > > 1. Decent documentation of the BEAM architecture and instruction set. > 2. Move most of the code from the "beam_load.c" module to the Erlang > compiler. This is the module that replaces generic BEAM instructions with > specialized instructions. This code would be much cleaner in Erlang than in > C, and it would also simplify the emulator (beam_load.c is the second > largest module in the emulator). > I quite agree - I have very recently done some experiments in loading code - admittedly for my old JAM machine but the results would equally apply to beam - Here I create *all* data structures (hash tables, code ...) as Erlang terms - squirt them out in my UBF (slightly optimized) - then to read the code I just mmap the file and do a parse_ubf (written in C) - this is *very* fast - the code just "falls" into the right place :-) I started building atom tables in Erlang that looked like this: {<<"aaa">, <<"bbb">, ... <<"<<<"} this is a sorted tuple of all the atoms in a module. Now I know that the memory layout of a tuple is a flat sequence of consecutive addresses, using this fact I can tweak things to get almost exactly the same data structure that a C program would have used - only do it all in Erlang - which is much easier ... What I'd like so see done is the following. Take a working machine (Beam, Jam ...) and *remove* as much as possible which still keeping the machine running (is this what re-factoring is) - I find it very difficult today to see what exactly is the essential code. I'd really like to see the entire system in two directories one C on Erlang - the emulator and the compiler with *no* dependencies and a *very* good documentation of all the instructions - /Joe From kostis@REDACTED Mon Sep 8 18:40:29 2003 From: kostis@REDACTED (Kostis Sagonas) Date: Mon, 8 Sep 2003 18:40:29 +0200 (MEST) Subject: Shared heap in R9C-0 ? Message-ID: <200309081640.h88GeTVZ003915@harpo.it.uu.se> Zoltan Toth wrote: > > A question mainly to Erlang developers: > > In the source README file for R9B the --enable-shared-heap > configure option was explicitely mentioned. > In R9C-0 it is not mentioned, but it still works. So when starting > the erlang machine built like this, it prints > > Erlang (BEAM) emulator version 5.3 [source] [hipe] [shared heap] [threads:0] > ^^^^^^^^^^^^^ > According to some measurements I made, it really provides some speedup. > So my question is: Why is it not mentioned in the configure help or > the README file ? Somebody from the Erlang/OTP team can provide some more definite answer, but my educated guess as somebody who is involved in the development of the shared heap system is that the reason why it is not mentioned in the README file is that the shared heap has been promoted from an optional to a by default available component of the R9C system. In R9C, the shared heap system is built by default and the configure option is thus not needed. You can actually start erlang as: erl -shared and you automatically get, what you previously got by configure --enable-shared-heap. > Is it planned to be removed ? >From the above, I suspect the answer is NO. > Is it not considered stable ? I am not sure what to say on this one... let me try the following: We (i.e. the HiPE team that has developed the shared heap) are not aware of any bugs. There might be bugs and performance anomalies in it, but unless Erlang programmers start using this and report their experiences to us, we will never find out. All I can say at this point is that we are committed to support this runtime system architecture and we welcome any feedback or user experiences. One last comment concerning: > According to some measurements I made, it really provides some speedup. This is true. In fact, (at least in theory) the shared heap can give "arbitrary" speedups in concurrent programs that communicate through large messages. However, beware that the garbage collector is currently not tuned for the shared heap, so in practice they can be slow-downs too. We are working on improving this. In the meantime, I repeat that we really, really welcome user feedback and programs that show speedups and slow-downs so that we can improve this shared heap runtime system architecture further. Kostis Sagonas for the HiPE team -- see http://www.csd.uu.se/projects/hipe/ From thomasl_erlang@REDACTED Mon Sep 8 20:36:10 2003 From: thomasl_erlang@REDACTED (Thomas Lindgren) Date: Mon, 8 Sep 2003 11:36:10 -0700 (PDT) Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: Message-ID: <20030908183610.79964.qmail@web41904.mail.yahoo.com> --- James Hague wrote: > 2. Move most of the code from the "beam_load.c" > module to the Erlang > compiler. This is the module that replaces generic > BEAM instructions with > specialized instructions. This code would be much > cleaner in Erlang than in > C, and it would also simplify the emulator > (beam_load.c is the second > largest module in the emulator). Bit syntax + magic extra BIFs for linking in code might do the trick. However, I'm not sure you need the detour of going through BEAM if you are doing your own implementation anyway. Some other options might be to write a backend for Core Erlang (I think Richard C. has been looking at this) or to write your own HIPE frontend. Though you are still stuck with the standard runtime system if you do this, which is a drawback if we want to do a "second-source". For an experimental code generator, generating .s files and statically linking them with a runtime system .so could work just fine. Perhaps one could use dlopen() and friends to do full dynamic linking, even. Or write a suitable new dynamic linker (e.g., parse ELF in Erlang, etc.) (Paging Tony Rogvall ... :-) Best, Thomas __________________________________ Do you Yahoo!? Yahoo! SiteBuilder - Free, easy-to-use web site design software http://sitebuilder.yahoo.com From luke@REDACTED Mon Sep 8 21:25:30 2003 From: luke@REDACTED (Luke Gorrie) Date: 08 Sep 2003 21:25:30 +0200 Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: <20030908183610.79964.qmail@web41904.mail.yahoo.com> References: <20030908183610.79964.qmail@web41904.mail.yahoo.com> Message-ID: Thomas Lindgren writes: > Some other options might be to write a backend for Core Erlang... I have done a small hack in this direction, though I'm convinced that it cannot lead to anything actually useful. (But it was fun to hack :-) It's a compiler from Core Erlang to Common Lisp, written in Lisp. It currently lacks concurrency completely, and much of the runtime system. It is complete enough to compile the standard 'lists' module and run functions like map and foreach, though. It's in the Jungerl under lib/claw/. claw.lisp is the compiler. The code is rather messy, but very simple. The design is a bit of fun in that it uses a regular LALR parser which returns a Common Lisp program as the parse tree (i.e. the compiler uses the parser for control flow). It's there if anyone wants to play with it :-) I don't see that it can ever be a BEAM competitor, at least with CMU Common Lisp. Having a complete Lisp system is great for prototyping, but would suck for a "finished product" that tries to totally hide the Lispiness (including ~20MB memory footprint :-). Not a good base for a "production implementation" as far as I can tell. It also doesn't seem much good for langauge experimentation, since by starting from core erlang you cut yourself off from the source language. To add language constructs would require hacking the regular Erlang compiler and its definition of Core Erlang. Probably better to write a plain interpreter for "an Erlang-like language" with Lisp syntax for such experimentation. (Prolog may be good for this too ;-) I kept a little journal while hacking this, since 'tis my first compiler. The last entry shows the basic workings and status: ---------------------------------------- 4th of May, 2003 Started trying to compile lists.erl from stdlib, which flushed out a bunch of bugs straight away. Now it compiles without warnings, and some functions are working fine: * (|lists|:|map/2| #'1+ '(1 2 3)) (2 3 4) * (|lists|:|foreach/2| #'print '(1 2 3)) 1 2 3 ATOM::|ok| though runtime support is obviously lacking in various other cases: * (|lists|:|flatmap/2| #'list '(1 2 3)) Error in KERNEL:%COERCE-TO-FUNCTION: the function ++ is undefined. I also have CLAW generating actual Lisp source files, and slightly tweaked the pretty printing. Here's the transformations of the standard lists:foreach/2 function, first in Erlang: foreach(F, [Hd|Tail]) -> F(Hd), foreach(F, Tail); foreach(_, []) -> ok. then Core Erlang: 'foreach'/2 = fun (_cor1,_cor0) -> case <_cor1,_cor0> of when 'true' -> do apply F (Hd) apply 'foreach'/2 (F, Tail) <_cor4,[]> when 'true' -> 'ok' <_cor3,_cor2> when 'true' -> primop 'match_fail' ({'function_clause',_cor3,_cor2}) end and into Lisp: (defun |foreach/2| ($_cor1 $_cor0) (match-case (values $_cor1 $_cor0) (($F ($Hd . $Tail)) @true (progn (funcall $F $Hd) (|foreach/2| $F $Tail))) (($_cor4 nil) @true @ok) (($_cor3 $_cor2) @true (primop "match_fail" #(@function_clause $_cor3 $_cor2))))) `match-case' is a Lisp macro that implements pattern matching. It's the only macro-defined construct, everything else is translated directly to regular Lisp in the parser. That is because Core Erlang maps so easily onto Common Lisp. (Notice that since 'fun(X) -> ... end' is compiled onto '(lambda (x) ...)', I can pass Lisp functions like #'1+ as fun-arguments to compiled Erlang code :-) Cheers, Luke From tony@REDACTED Mon Sep 8 23:15:01 2003 From: tony@REDACTED (Tony Rogvall) Date: 08 Sep 2003 23:15:01 +0200 Subject: Erlang on XBOX In-Reply-To: <200309081446.h88EkCH03976@bonsai.fernuni-hagen.de> References: <200309081446.h88EkCH03976@bonsai.fernuni-hagen.de> Message-ID: <1063055701.7829.13.camel@bit.hemma.se> On Mon, 2003-09-08 at 16:46, Marc Ernst Eddy van Woerkom wrote: > > root@REDACTED:~# uname -a > > Linux xbox.localdomain.local 2.4.21-xbox #1 Mon Jul 14 11:12:49 UTC 2003 > > root@REDACTED:~# erl > > Erlang (BEAM) emulator version 5.3 [source] [hipe] [threads:0] > > Cool. > > What do I need - an XBox, some game with weakness, a network card? > And does this still beat cheap new PCs? > You need: (see http://xbox-linux.sourceforge.net/) 1. X-Box 2. MechAssault - The game (only once!) 3. USB memory - either camera and some USB cable patch or use the "Action Replay" memory card, the linux installer can now be found at "Action Replay" site :-) 4. CD-RW with a linux distro. I think it beats the PC with a small margin, but you can use your X-Box as DVD player/CD music player/Linux computer and of course play X-Box games ;-) I intend to buy 9 more and use them in a linux cluster, for testing purposes. But think about what you can do with a linux cluster with high speed graphics card in them... Have fun. -- Tony Rogvall -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 307 bytes Desc: This is a digitally signed message part URL: From ulf.wiger@REDACTED Mon Sep 8 22:09:41 2003 From: ulf.wiger@REDACTED (Ulf Wiger) Date: Mon, 08 Sep 2003 22:09:41 +0200 Subject: 'news' not updated Message-ID: <3F5CE205.833A3391@telia.com> If I may... the "News" section at www.erlang.org has not been updated in a while. It could be because not much is happening, but at least the R9C-0 release could have been mentioned. As it looks now, not much has happened since R9B-1. (: /Uffe From michael@REDACTED Tue Sep 9 00:38:13 2003 From: michael@REDACTED (Michael Hobbs) Date: Mon, 8 Sep 2003 17:38:13 -0500 (CDT) Subject: Compiling drivers with MinGW? Message-ID: <1335.66.41.245.83.1063060693.squirrel@mail.hobbshouse.org> Has anyone been able to create a driver DLL using MinGW? The problem that I'm running into is that the libraries in $ERL_TOP/lib/erl_interface/lib are in MSVC format. Has anyone been able to either: a) Convert the .lib's to GCC-compliant .a's? b) Compile the erl_interface source using MinGW? I suppose as a last resort, I could change the erl_interface build to generate a DLL instead of static libraries, but that would be less than optimal. Any help is greatly appreciated. Thanks, - Michael Hobbs From ok@REDACTED Tue Sep 9 01:38:10 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Tue, 9 Sep 2003 11:38:10 +1200 (NZST) Subject: Packages in Erlang: new documentation Message-ID: <200309082338.h88NcARH155800@atlas.otago.ac.nz> A Concerning hundreds of files in a directory: Who says Erlang modules, in any form, have to be in a directory? In the MVC and CMS world, it used to be normal to use "partitioned data sets" (think of UNIX ar(1), arguably better engineered). For example, instead of FOO.C FOO.H BAR.C BAR.H you might have CSOURCE(FOO) HEADER(FOO) CSOURCE(BAR) HEADER(BAR) where CSOURCE and HEADER were each a single file, containing subfiles. (For another analogy, think of nested OLE containers.) With block sizes slowly climbing upwards, the space waste of having one file per "object" can be quite high. For example, I recently tried to install a certain (non-Erlang) system on a Mac with a 4GB disc where the system block size was (I am not making this up) 60kB. A one line file still took a full 60kB, and the disc space ran out with less than about 10% of the space actually _used_. For another example, an old version of Erlang I have lying around requires 203 million bytes in 13.5 thousand files. On a file system with 8kB blocks, it actually takes 267 million bytes, wasting 64MB, adding an extra 31% of waste space to useful information. In one set of files, I've measured the waste space : useful data ratio as 1.6 : 1, that's about 60% waste space. UNIX ar(1) format isn't very wonderful, because (1) it only allows 16 characters for a file name (man -s 3HEAD ar IKYN) (2) the directory information is scattered through the file, so it is inefficient to read just one member. But who says we have to use ar(1) format, eh? B. Concerning search paths: Search paths can be a real pain. Suppose there are two directories: /usr/ucb/bin/ ... cc, pr, ... /usr/bin/ ... cc, pr, ... and I want the cc from /usr/bin and the pr from /usr/ucb/bin. Then there is _no_ ordering of the directories in the search path that will give me what I want. Throw in over a dozen different installed programs each with its own idea of what it expects to be in the path, and you get some idea of why it has been a couple of years since I've been able to use Texinfo. There's a particular pain with search paths. Here is a summary of just *half* the directories in my $PATH: 297 /home/users/okeefe_r/commands.d 116 /opt/SUNWspro/bin 49 /usr/ccs/bin 615 /usr/bin 376 /usr/sbin 263 /usr/local/bin 105 /usr/ucb 142 /usr/openwin/bin 137 /usr/dt/bin The commands in ~/commands.d/ I am responsible for; I know what they do. But of the 2100 total commands, I haven't the faintest idea of what more than about 600 do: new ones keep on being added, there are replicates and clashes between these, and I have by now no reason to expect what I have to be a consistent set. Quite often I have a directory with more than a hundred commands in my search path just for the sake of two or three commands. (These days, I prefer adding a symbolic link from ~/commands.d to adding a whole directory.) If it is somewhere between "nightmarishly difficult" and "impossible" to manage a search path with a few thousand UNIX commands, it has to be worse managing lots of Erlang modules. With modules, you have the problem that a flotilla of modules may need access to each other, while only one or two of them should be referred to from elsewhere. Putting them in a global namespace, *any* global namespace, simple or dotted, doesn't solve this problem. C. On packages providing one entry in a load path: This is also an advantage of LACE, an advantage which is _easily_ gained WITHOUT INTRODUCING DOTTED MODULE NAMES. The thing that doesn't scale is the global namespace for modules. Packages postpone the collapse, but do not prevent it; they are *still* a global namespace for modules. They just plain don't go to the root of the problem. Dotted name systems are a dime a dozen. The thing that was really innovative in Java packages was tying them to an existing system of names which has * LEGAL OWNERSHIP of names, and a * LEGAL REGISTRY of owned names. It's not names like java.awt.event that are the interesting bit, but names like com.icl.saxon.tree, which is tied to the legally owned domain name "icl.com". From ok@REDACTED Tue Sep 9 01:55:00 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Tue, 9 Sep 2003 11:55:00 +1200 (NZST) Subject: Wither Self Message-ID: <200309082355.h88Nt0Iq385072@atlas.otago.ac.nz> Joe Armstrong wrote: Shouldn't there be a Self in funs? Fac = fun(0) -> 1; (N) -> N*Self(N-1) end Well, if the compiler were just a touch smarter, you wouldn't need it. If you have = ... ... then the check for unbound variables in should ask whether any variable will still be unbound *after* the pattern is matched instead of whether any variable is unbound *before* the pattern match. Then you could just write Fac = fun(0) -> 1; N -> N * Fac(N-1) end, without needing Self. This would also handle mutual recursion: {Even, Odd} = {fun(0) -> true; (N) -> Odd( N-1) end, fun(0) -> false; (N) -> Even(N-1) end}, which the Self proposal would not deal with at all. From raimo@REDACTED Tue Sep 9 09:23:22 2003 From: raimo@REDACTED (Raimo Niskanen) Date: Tue, 09 Sep 2003 09:23:22 +0200 Subject: Wither Self References: <200309082355.h88Nt0Iq385072@atlas.otago.ac.nz> Message-ID: If the compiler would check for unbound variables in the right side of match expression *after* the pattern match, how would the following be treated? {Even, Odd, Strange} = {fun(0) -> true; (N) -> Odd( N-1) end, fun(0) -> false; (N) -> Even(N-1) end, Strange}, when Strange is bound vs unbound, or {Even, Odd, Strange} = {fun(0) -> true; (N) -> Odd( N-1) end, fun(0) -> false; (N) -> Even(N-1) end, {very,Strange}}, or even {Even, Odd, Strange} = {fun(0) -> true; (N) -> Odd( N-1) end, fun(0) -> false; (N) -> Even(N-1) end, case Strange() of true -> fun()->Odd(0)end; false -> fun()->Even(0)end end}, or do you mean that it is just fun()s unbound variables that should be checked after the pattern match binding? / Raimo Niskanen, Erlang/OTP, Ericsson AB Richard A. O'Keefe wrote: > Joe Armstrong wrote: > Shouldn't there be a Self in funs? > > Fac = fun(0) -> 1; > (N) -> N*Self(N-1) end > > Well, if the compiler were just a touch smarter, you wouldn't need it. > > If you have > = ... ... > then the check for unbound variables in should ask whether > any variable will still be unbound *after* the pattern is matched > instead of whether any variable is unbound *before* the pattern match. > > Then you could just write > > Fac = fun(0) -> 1; N -> N * Fac(N-1) end, > > without needing Self. This would also handle mutual recursion: > > {Even, Odd} = > {fun(0) -> true; (N) -> Odd( N-1) end, > fun(0) -> false; (N) -> Even(N-1) end}, > > which the Self proposal would not deal with at all. > From vlad_dumitrescu@REDACTED Tue Sep 9 10:01:47 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Tue, 9 Sep 2003 10:01:47 +0200 Subject: Wither Self References: <200309082355.h88Nt0Iq385072@atlas.otago.ac.nz> Message-ID: > > {Even, Odd} = > > {fun(0) -> true; (N) -> Odd( N-1) end, > > fun(0) -> false; (N) -> Even(N-1) end}, Hi, is this so much simpler to write and understand than even(0)->true; even(N)->odd(N-1). odd(0)->false; odd(N)->even(N-1). Even = fun even/1, Odd=fun odd/1, ? Having the funs local may be simpler to write in some cases, but once the fun is larger than those above, the code gets rather difficult to read. regards, /Vlad From bjorn@REDACTED Tue Sep 9 10:42:33 2003 From: bjorn@REDACTED (Bjorn Gustavsson) Date: 09 Sep 2003 10:42:33 +0200 Subject: Shared heap in R9C-0 ? In-Reply-To: <3F5C8B5F.90700@eth.ericsson.se> References: <3F5C8B5F.90700@eth.ericsson.se> Message-ID: Zoltan Peter Toth writes: > Erlang (BEAM) emulator version 5.3 [source] [hipe] [shared heap] [threads:0] > ^^^^^^^^^^^^^ > According to some measurements I made, it really provides some speedup. > So my question is: Why is it not mentioned in the configure help or the README file ? > Is it planned to be removed ? Is it not considered stable ? It is not considered stable yet. /Bjorn -- Bj?rn Gustavsson Ericsson Utvecklings AB bjorn@REDACTED ?T2/UAB/F/P BOX 1505 +46 8 727 56 87 125 25 ?lvsj? From bjorn@REDACTED Tue Sep 9 13:57:27 2003 From: bjorn@REDACTED (Bjorn Gustavsson) Date: 09 Sep 2003 13:57:27 +0200 Subject: Compiling drivers with MinGW? In-Reply-To: <1335.66.41.245.83.1063060693.squirrel@mail.hobbshouse.org> References: <1335.66.41.245.83.1063060693.squirrel@mail.hobbshouse.org> Message-ID: "Michael Hobbs" writes: > Has anyone been able to create a driver DLL using MinGW? The problem that > I'm running into is that the libraries in $ERL_TOP/lib/erl_interface/lib > are in MSVC format. Has anyone been able to either: > > a) Convert the .lib's to GCC-compliant .a's? > b) Compile the erl_interface source using MinGW? > > I suppose as a last resort, I could change the erl_interface build to > generate a DLL instead of static libraries, but that would be less than > optimal. > > Any help is greatly appreciated. Thanks, > - Michael Hobbs > > > Answer from Patrik Nyblom: Compiling drivers with MinGW requires a small patch to the header file in R9C, which will be included in our next release. However erl_interface is a completely other thing. It needs some rewriting to work with mingw, of which one is to generate a DLL as an alternative to the static libraries. You said a DLL is less than optimal, I don't really understand why, DLL's are far more flexible than static libraries and ought to be the way to proceed in anyway. As a nice bi-product of using shared libraries, the erl_interface libraries can be used by any compiler. If one chooses .a or .lib files for the import library is then a matter of taste. MinGW can handle either. The free esdl library for erlang uses MinGW to compile, in fact it patches the said header in the makefiles (to a temp directory). It haowever does not use erl_interface for encoding/decoding, a handwritten protocol between erlang and the driver is far more efficient. It can also be said that another free library, erlgtk, which uses erl_interface has to be compiled with VC++. So, the MinGW comatibility is a problem, abd as far as I know, the DLL solution is the most feasible. In it's current state, erl_interface cannot even be recompiled using MinGW, it uses microsoft specific directives that MinGW has not implemented. If all goes well, the next windows-release (R9C-1) will contain a erl_interface working wint MinGW as well, but no promises yet :-) /Patrik, OTP -- Bj?rn Gustavsson Ericsson Utvecklings AB bjorn@REDACTED ?T2/UAB/F/P BOX 1505 +46 8 727 56 87 125 25 ?lvsj? From HEINRICH.VENTER@REDACTED Tue Sep 9 14:54:59 2003 From: HEINRICH.VENTER@REDACTED (HEINRICH VENTER) Date: Tue, 09 Sep 2003 14:54:59 +0200 Subject: io:format error Message-ID: Hi I am frankly stumped by this. the following lines of code finalize_result({TransactionData, R_ResponseCode, TransactionAmount, EndBalance, Flags_2, CostingInfo}, ConfigurationData) -> io:format("~nTransactionAmount = ~p", [TransactionAmount]), io:format("~n........ Finalize Result ..........."), io:format("~n<<< leah:close_connection >>>"), io:format("~nTransactionAmount voor leah call : ~p", [TransactionAmount]), %% more processing follows causes the following VERY odd behavior TransactionAmount = 0.00000e+0 ........ Finalize Result ........... <<< leah:close_connection >>> TransactionAmount voor leah call : {io_request, <0.115.0>, <0.112.0>, {put_chars, io_lib, format, ["~nTransactionAmount = ~p",[0.00000e+0]]}} This does not happen consistantly however... it happens every now and then. It would seem that the TransactionAmount variable gets re-bound to the code in some way. I am frankly at a loss. HeeEEeEEeLp! -]-[einrich Teba Bank ##################################################################################### The information contained in this message and or attachments is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any system and destroy all copies. ##################################################################################### From HEINRICH.VENTER@REDACTED Tue Sep 9 15:22:32 2003 From: HEINRICH.VENTER@REDACTED (HEINRICH VENTER) Date: Tue, 09 Sep 2003 15:22:32 +0200 Subject: format error Message-ID: We are using OTP8 at the moment (historic reasons) The code is executing on a Sun U60. The problem is that the code between the first output and the second ouput CAN not change the value of a bound variable!??!! The code below is exactly as it appears, nothing deleted. We seem to have "fixed" the problem by outputting the following finalize_result({TransactionData, R_ResponseCode, TransactionAmount, EndBalance, Flags_2, CostingInfo}, ConfigurationData) -> io:format("~nTransactionAmount = ~p", [TransactionAmount]), io:format("~n........ Finalize Result ..........."), io:format("~n<<< leah:close_connection >>>"), io:format("x"), io:format("~nTransactionAmount voor leah call : ~p", [TransactionAmount]), io:format("x"), (note the two lines that output an x) But this is a HACK at best. -]-[einrich Teba Bank ##################################################################################### The information contained in this message and or attachments is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any system and destroy all copies. ##################################################################################### From luke@REDACTED Tue Sep 9 16:23:24 2003 From: luke@REDACTED (Luke Gorrie) Date: 09 Sep 2003 16:23:24 +0200 Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: <3F5B6E51.16454.289DB0@localhost> References: <3F5B6E51.16454.289DB0@localhost> Message-ID: "James Hague" writes: > (One idea I've mused about is doing away with the C implementation of > the BEAM emulator entirely, and writing the core in a custom mid- > level language implemented in Erlang.) Have you considered using existing mid-level languages instead? If so, are there any that seem particularly qualified/disqualified? Cheers, Luke From michael@REDACTED Tue Sep 9 16:31:50 2003 From: michael@REDACTED (Michael Hobbs) Date: Tue, 9 Sep 2003 09:31:50 -0500 (CDT) Subject: Compiling drivers with MinGW? In-Reply-To: References: <1335.66.41.245.83.1063060693.squirrel@mail.hobbshouse.org> Message-ID: <1433.66.41.245.83.1063117910.squirrel@mail.hobbshouse.org> Bjorn Gustavsson said: > You said a DLL is less than optimal, I don't > really understand why, DLL's are far more flexible than static libraries > and ought to be the way to proceed in anyway. If it is part of the standard Erlang distribution, it wouldn't be much of a problem. I just wasn't looking forward to packaging yet another DLL along with my driver DLL and making sure that it is in the $PATH. (Not to mention versioning issues that can occur with DLL's.) > If all goes well, the next windows-release (R9C-1) will contain a > erl_interface working wint MinGW as well, but no promises yet :-) Excellent. Thanks much. - Michael Hobbs From crav@REDACTED Tue Sep 9 11:47:25 2003 From: crav@REDACTED (crav@REDACTED) Date: Tue, 09 Sep 2003 11:47:25 Subject: Hi Message-ID: <200309091458.h89EwD6S006507@mails.conexion.com.py> I try to install megaco_session-0.4 but my result is: make .... .... ********************* -DVERSION="\"0.4\"" mg.o mg_user.o -o mg -L/usr/erlang/megaco_session-0.4/priv/lib -L/usr/local/lib/erlang/lib/ic-4.2.1/priv/lib -L/usr/local/lib/erlang/lib/erl_interface-3.4/lib -lmegaco_session -lic -lerl_interface -lei -lnsl mg.o: In function `einit': mg.o(.text+0xdd8): undefined reference to `erl_gethostbyname' collect2: ld returned 1 exit status make[3]: *** [mg] Error 1 make[3]: Saliendo directorio `/usr/erlang/megaco_session-0.4/examples/simple_MG' make[2]: *** [all] Error 2 make[2]: Saliendo directorio `/usr/erlang/megaco_session-0.4/examples/simple_MG' make[1]: *** [all] Error 2 make[1]: Saliendo directorio `/usr/erlang/megaco_session-0.4/examples' make: *** [all] Error 2 ********************** what can be wrong??? First i install otp_src_R9C-0, then i try with megaco_session-0.4 and that fail!!! Help please Hilfe bitte ================================================= Webmail v.2.0 - Producido por R&D http://webmail.conexion.com.py From Erik.Stenman@REDACTED Tue Sep 9 15:15:35 2003 From: Erik.Stenman@REDACTED (Erik Stenman) Date: Tue, 9 Sep 2003 15:15:35 +0200 Subject: format error In-Reply-To: Message-ID: <007501c376d4$74457840$2d9ab280@lamppc36> It looks like it could be a deferred fp-exception. Newer versions of the BEAM uses native fp support for some fp operations. If you have e.g. a divide by zero somewhere this can trigger a fp exception in the hardware of the machine if this is not trapped at the right point it might show up as an Erlang exception at some other point in your program. If this is the case then there is a bug in the BEAM. Which Erlang version are you using and on what kind of hardware are you running? /Erik (Happi) > -----Original Message----- > From: owner-erlang-questions@REDACTED > [mailto:owner-erlang-questions@REDACTED] On Behalf Of > HEINRICH VENTER > Sent: den 9 september 2003 14:55 > To: erlang-questions@REDACTED > Subject: io:format error > > > Hi > > I am frankly stumped by this. > > the following lines of code > > finalize_result({TransactionData, R_ResponseCode, > TransactionAmount, EndBalance, Flags_2, CostingInfo}, > ConfigurationData) -> > io:format("~nTransactionAmount = ~p", [TransactionAmount]), > io:format("~n........ Finalize Result ..........."), > io:format("~n<<< leah:close_connection >>>"), > > io:format("~nTransactionAmount voor leah call : ~p", > [TransactionAmount]), > %% more processing follows > > causes the following VERY odd behavior > > TransactionAmount = 0.00000e+0 > ........ Finalize Result ........... > <<< leah:close_connection >>> > TransactionAmount voor leah call : {io_request, > <0.115.0>, > <0.112.0>, > {put_chars, > io_lib, > format, > > ["~nTransactionAmount = ~p",[0.00000e+0]]}} > > This does not happen consistantly however... it happens every > now and then. It would seem that the TransactionAmount > variable gets re-bound to the code in some way. > > I am frankly at a loss. HeeEEeEEeLp! > > -]-[einrich > Teba Bank > > ############################################################## > ####################### > The information contained in this message and or attachments > is intended only for the person or entity to which it is > addressed and may contain confidential and/or privileged > material. Any review, retransmission, dissemination or other > use of, or taking of any action in reliance upon, this > information by persons or entities other than the intended > recipient is prohibited. If you received this in error, > please contact the sender and delete the material from any > system and destroy all copies. > ############################################################## > ####################### > From Erik.Stenman@REDACTED Tue Sep 9 16:44:59 2003 From: Erik.Stenman@REDACTED (Erik Stenman) Date: Tue, 9 Sep 2003 16:44:59 +0200 Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: Message-ID: <008b01c376e0$f175d8d0$2d9ab280@lamppc36> I would suggest using the Icode language in the HiPE compiler, It is a very simple language with realy only 15 different instructions. And there is already a compiler from Erlang or BEAM to Icode. (An Erlang->Core Erlang->Icode compiler is on its way.) To write an interpreter for this language in Erlang or C should be very easy. A simple example: -module(len). -export([len/1]). len([]) -> []; len([_|R]) -> len(R). ---- bash> erlc +native +\{hipe,\[\{pp_icode,\{file,"len.icode"\}\}\]\} bash> cat len.icode len:len(v0) -> %% Info:['Not a closure','Leaf function'] 1: _ := redtest() (primop) goto 4 4: if is_cons(v0) then 3 (0.50) else 6 3: v5 := unsafe_hd(v0) (primop) v0 := unsafe_tl(v0) (primop) goto 1 6: if is_nil(v0) then 5 (0.50) else 2 5: v0 := 0 return(v0) 2: v3 := function_clause fail(fault, [v3]) %% Data: len:module_info() -> %% Info:['Not a closure','Leaf function'] 1: _ := redtest() (primop) goto 10 10: v0 := [] return(v0) %% Data: len:module_info(v0) -> %% Info:['Not a closure','Leaf function'] 1: _ := redtest() (primop) goto 14 14: v0 := [] return(v0) %% Data: --- I'll be glad to give anyone intrested in such a project more information about Icode. /Erik (Happi) Stenman > -----Original Message----- > From: owner-erlang-questions@REDACTED > [mailto:owner-erlang-questions@REDACTED] On Behalf Of Luke Gorrie > Sent: den 9 september 2003 16:23 > To: James Hague > Cc: erlang-questions@REDACTED > Subject: Re: BEAM documentation (was Re: Packages in Erlang...) > > > "James Hague" writes: > > > (One idea I've mused about is doing away with the C > implementation of > > the BEAM emulator entirely, and writing the core in a custom mid- > > level language implemented in Erlang.) > > Have you considered using existing mid-level languages > instead? If so, are there any that seem particularly > qualified/disqualified? > > Cheers, > Luke > > From luke@REDACTED Tue Sep 9 18:19:28 2003 From: luke@REDACTED (Luke Gorrie) Date: 09 Sep 2003 18:19:28 +0200 Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: <008b01c376e0$f175d8d0$2d9ab280@lamppc36> References: <008b01c376e0$f175d8d0$2d9ab280@lamppc36> Message-ID: "Erik Stenman" writes: > I would suggest using the Icode language in the HiPE compiler, > It is a very simple language with realy only 15 different instructions. > And there is already a compiler from Erlang or BEAM to Icode. > (An Erlang->Core Erlang->Icode compiler is on its way.) Do you implement e.g. the bit syntax in Icode, or is that done in the runtime system? And will those 15 ops be enough or do you fear Icode feature-creep? One thing I find attractive about James's idea of using a "mid-level" language as the target is that it makes it easy to write things like the bit syntax: you take the bit-pattern and generate straight forward code e.g. in terms of logand, bitshift, etc. Then you let the mid-level-language compiler worry about making _that_ fast. For example, I have implemented a bit syntax is Common Lisp, and it was very easy. (Actually it was designed by Frode Vatvedt Fjeld, and I wrote a compiler-based backend for it as outlined above.) My compiler is 147 lines of code, very simple, and generates code that AFAICT the CL compiler should be able to do great things with: it includes full type information and does "the business" with low-level LDB/DPB/AREF operations. i.e. it is a "production quality" bit syntax. It's a different bit syntax to the Erlang one. Essentially you define structures/records which include the details of how to encode/decode them as binary. For example, here is the Internet Protocol (IP) header: (define-binary-bitfield-struct iph () (version nil :binary-type ip-version) (hlen nil :binary-type ip-header-length) (tos nil :binary-type ip-type-of-service) (total-len nil :binary-type ip-total-length) (id nil :binary-type ip-identification) (flags nil :binary-type ip-flags) (fragment-offset nil :binary-type ip-fragment-offset) (ttl nil :binary-type ip-time-to-live) (protocol nil :binary-type ip-protocol) (checksum nil :binary-type ip-header-checksum) (source nil :binary-type ip-addr) (dest nil :binary-type ip-addr) (options '())) Then there are separate declarations saying that `ip-addr' is four octets and maps onto a vector/array, that ip-fragment-offset is an unsigned 13-bit value, and so on. Then you can ask the compiler to make a function that reads or writes this structure to/from a byte buffer. Here is the read function that it generates (as pretty-printed by Lisp): (defun iph-to-vector (object &optional (buffer-spec 512)) (let ((buffer (make-buffer buffer-spec))) "Encode an IP header as a vector." (let ((bit-buffer 0) (bits-buffered 0) (bytes-written 0)) (declare (type (simple-array (unsigned-byte 8) (*)) buffer) (type iph object) (type (unsigned-byte 8) bit-buffer) (type (integer 0 8) bits-buffered) (type fixnum bytes-written)) (labels ((output-byte! (value) (setf (aref buffer bytes-written) value) (incf bytes-written)) (output-bits! (value bits) "Output BITS of VALUE (buffered into whole bytes.)" (declare (type fixnum value bits)) (loop (let ((take-bits (min bits (- 8 bits-buffered)))) (setf bit-buffer (dpb (ldb (byte take-bits (- bits take-bits)) value) (byte take-bits (- 8 (+ take-bits bits-buffered))) bit-buffer)) (incf bits-buffered take-bits) (decf bits take-bits) (when (= 8 bits-buffered) (output-byte! bit-buffer) (setf bits-buffered 0)) (when (zerop bits) (return t)))))) (let ((object object)) (output-bits! (slot-value object 'version) 4) (output-bits! (slot-value object 'hlen) 4) (output-bits! (slot-value object 'tos) 8) (output-bits! (slot-value object 'total-len) 16) (output-bits! (slot-value object 'id) 16) (output-bits! (slot-value object 'flags) 3) (output-bits! (slot-value object 'fragment-offset) 13) (output-bits! (slot-value object 'ttl) 8) (output-bits! (slot-value object 'protocol) 8) (output-bits! (slot-value object 'checksum) 16) (let ((object (slot-value object 'source))) (let ((object (slot-value object 'value))) (dotimes (i 4) (output-bits! (aref object i) 8)))) (let ((object (slot-value object 'dest))) (let ((object (slot-value object 'value))) (dotimes (i 4) (output-bits! (aref object i) 8))))) (adjust-array buffer (list bytes-written)))))) I like this a lot: - Compiler is very simple. - Generated code is perfectly readable (if you know CL, and can understand my probably suboptimal `output-bits!' algorithm!) - Generated code includes full type information for the Lisp compiler. Is there room for this programming style in the guts of an Erlang implementation? I promise to be an enthusiastic contributor if so :-) PS, Compiler is here: http://www.bluetail.com/~luke/misc/lisp/binary-rw-gen.html Definitions of the TCP/IP suite's PDUs is here: http://www.bluetail.com/~luke/misc/lisp/netlib-structures.html PPS, wanna see a working ethernet switch that fits on one screen? :-) http://www.bluetail.com/~luke/misc/lisp/switch.html Cheers, Luke From mlogan@REDACTED Wed Sep 10 00:12:37 2003 From: mlogan@REDACTED (Martin J. Logan) Date: 09 Sep 2003 17:12:37 -0500 Subject: Doc or gen_event:notify/2 Error! Message-ID: <1063145556.2708.32.camel@dhcp-lom-194-186.futuresource.com> Hello, I have found an inconsistency in the docs. The docs indicate that the return value for gen_event notify is as follows: notify(EventMgrRef, Event) -> ok This makes sense as it is asynchronous. I pass a registered name to a notify call and if the name is not registered I get an exit(). It is the same badarg exit that one would expect from unregistered_name ! message I think that either the docs should be changed to notify(EventMgrRef, Event) -> ok | exit() or more preferably the notify/2 function should not exit. Cheers, Martin OUTPUT: gen_event:notify(martin, martin). =ERROR REPORT==== 9-Sep-2003::17:05:56 === Error in process <0.31.0> with exit value: {badarg,[{gen_event,send,2},{erl_eval,do_apply,5},{shell,eval_loop,2}]} ** exited: {badarg,[{gen_event,send,2}, {erl_eval,do_apply,5}, {shell,eval_loop,2}]} ** From ok@REDACTED Wed Sep 10 04:05:53 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Wed, 10 Sep 2003 14:05:53 +1200 (NZST) Subject: Wither Self Message-ID: <200309100205.h8A25rE5354689@atlas.otago.ac.nz> Raimo Niskanen wrote: If the compiler would check for unbound variables in the right side of match expression *after* the pattern match, how would the following be treated? {Even, Odd, Strange} = {fun(0) -> true; (N) -> Odd( N-1) end, fun(0) -> false; (N) -> Even(N-1) end, Strange}, I most certainly did NOT say "check for unbound variables in the right side of match expression"! What I wrote was quite explicit: > If you have > = ... ... vvvvvvv > then the check for unbound variables in should ask whether ^^^^^^^ > any variable will still be unbound *after* the pattern is matched > instead of whether any variable is unbound *before* the pattern match. In your example, {Even, Odd, Strange} = {fun(0) -> true; (N) -> Odd( N-1) end, ^______________ *IS* in a fun(0) -> false; (N) -> Even(N-1) end, ^______________ *IS* in a Strange}, ^_______________________________________ is *NOT* in a The change applies only to , and I should have said that it should apply only to those which are only enclosed by [..] {..} constructors; a which is an argument of a function call should be checked like the rest of the expression. In the example {Even, Odd, Strange} = {fun(0) -> true; (N) -> Odd( N-1) end, ^______________ *IS* in a fun(0) -> false; (N) -> Even(N-1) end, ^______________ *IS* in a {very,Strange}}, ^_________________________________ is *NOT* in a the alleged problem is again fictitious. or do you mean that it is just fun()s unbound variables that should be checked after the pattern match binding? Yes. That's why I _said_ so. From ok@REDACTED Wed Sep 10 04:19:07 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Wed, 10 Sep 2003 14:19:07 +1200 (NZST) Subject: Wither Self Message-ID: <200309100219.h8A2J79V362642@atlas.otago.ac.nz> "Vlad Dumitrescu" wrote: > > {Even, Odd} = > > {fun(0) -> true; (N) -> Odd( N-1) end, > > fun(0) -> false; (N) -> Even(N-1) end}, is this so much simpler to write and understand than even(0)->true; even(N)->odd(N-1). odd(0)->false; odd(N)->even(N-1). Even = fun even/1, Odd=fun odd/1, Obviously this example would be even simpler as Even = fun (N) -> case N rem 2 of 0 -> true; 1 -> false end, Odd = fun (N) -> case N rem 2 of 1 -> true; 0 -> false end, An oversimplified example constructed to make a different point entirely (whether my example or Joe Armstrong's) should never be mistaken for the expected or most typical use of something. ? Having the funs local may be simpler to write in some cases, but once the fun is larger than those above, the code gets rather difficult to read. I presume that Joe's reason for wanting this is to handle the quite common case where you need a recursive function that can refer to a local variable. In that case, it isn't *possible* to just move the function to the top level; you have to do lambda-lifting. And then the function you actually write has a different arity. And then you can no longer just pass its name, you have to introduce yet another fun() to capture the local variable(s) you want. In short, there are cases where locally defined recursive functions are harder to read than the alternatives, and, based on Haskell and ML experience, there are cases where they are much easier to read than the alternatives. From gunilla@REDACTED Wed Sep 10 08:08:28 2003 From: gunilla@REDACTED (Gunilla Arendt) Date: Wed, 10 Sep 2003 08:08:28 +0200 Subject: Doc or gen_event:notify/2 Error! References: <1063145556.2708.32.camel@dhcp-lom-194-186.futuresource.com> Message-ID: <3F5EBFDC.BD01317C@erix.ericsson.se> Snip from the gen_event man page: "Unless otherwise stated, all functions in this module fail if the specified event manager does not exist or if bad arguments are given" The same goes for gen_server and gen_fsm. Regards, Gunilla "Martin J. Logan" wrote: > > Hello, > I have found an inconsistency in the docs. > > The docs indicate that the return value for gen_event notify is as > follows: > > notify(EventMgrRef, Event) -> ok > > This makes sense as it is asynchronous. I pass a registered name to a > notify call and if the name is not registered I get an exit(). It is the > same badarg exit that one would expect from > > unregistered_name ! message > > I think that either the docs should be changed to > > notify(EventMgrRef, Event) -> ok | exit() > > or more preferably the notify/2 function should not exit. > > Cheers, > Martin > > OUTPUT: > > gen_event:notify(martin, martin). > > =ERROR REPORT==== 9-Sep-2003::17:05:56 === > Error in process <0.31.0> with exit value: > {badarg,[{gen_event,send,2},{erl_eval,do_apply,5},{shell,eval_loop,2}]} > > ** exited: {badarg,[{gen_event,send,2}, > {erl_eval,do_apply,5}, > {shell,eval_loop,2}]} ** -- _____Gunilla Arendt______________________________________________ EAB/UKH/KD Erlang/OTP Product Development Gunilla.Arendt@REDACTED +46-8-7275730 ecn 851 5730 From DANIESC.SCHUTTE@REDACTED Wed Sep 10 09:42:56 2003 From: DANIESC.SCHUTTE@REDACTED (DANIESC SCHUTTE) Date: Wed, 10 Sep 2003 09:42:56 +0200 Subject: Problem's installing R9C-0 Message-ID: Morning all, when trying to install R9C-0 I get the following error - please check the attached install.txt file. Any suggestions? ##################################################################################### The information contained in this message and or attachments is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any system and destroy all copies. ##################################################################################### -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: install.txt URL: From bry@REDACTED Wed Sep 10 10:33:23 2003 From: bry@REDACTED (bryan) Date: Wed, 10 Sep 2003 10:33:23 +0200 Subject: yaws question Message-ID: <003c01c37776$337a5f90$2001a8c0@bryans> What authentication methods does Yaws support? -------------- next part -------------- An HTML attachment was scrubbed... URL: From klacke@REDACTED Wed Sep 10 12:37:24 2003 From: klacke@REDACTED (Klacke) Date: Wed, 10 Sep 2003 12:37:24 +0200 Subject: yaws question In-Reply-To: <003c01c37776$337a5f90$2001a8c0@bryans> References: <003c01c37776$337a5f90$2001a8c0@bryans> Message-ID: <20030910103724.GA29560@bluetail.com> On Wed, Sep 10, 2003 at 10:33:23AM +0200, bryan wrote: > What authentication methods does Yaws support? > 1. Normal HTTP auth and there only the Basic auth method. 2. The prefered method, session/cookie based auth. /klacke -- Claes Wikstrom -- Caps lock is nowhere and Alteon WebSystems -- everything is under control http://www.bluetail.com/~klacke cellphone: +46 70 2097763 From raimo@REDACTED Wed Sep 10 15:18:06 2003 From: raimo@REDACTED (Raimo Niskanen) Date: Wed, 10 Sep 2003 15:18:06 +0200 Subject: Problem's installing R9C-0 References: Message-ID: What kind of machine are you installing on? It seems as the configure script (using the autoconf macro AC_CHECK_SIZEOF) cannot determine the size of neither of "short, int, long, void *, long long, size_t, off_t". This means that it somehow failed to compile and run a little test program that prints "sizeof(TYPE)" to a temporary file and parse the result. Very strange. This is a standard configure script macro, they usually perform well. / Raimo Niskanen, Erlang/OTP, Ericsson AB DANIESC SCHUTTE wrote: > Morning all, > > when trying to install R9C-0 I get the following error - please check the attached install.txt file. > > Any suggestions? > > > ##################################################################################### > The information contained in this message and or attachments is intended > only for the person or entity to which it is addressed and may contain > confidential and/or privileged material. Any review, retransmission, > dissemination or other use of, or taking of any action in reliance upon, > this information by persons or entities other than the intended recipient > is prohibited. If you received this in error, please contact the sender and > delete the material from any system and destroy all copies. > ##################################################################################### > > > ------------------------------------------------------------------------ > > bash-2.03# ./configure > checking host system type... sparc-sun-solaris2.8 > checking for GNU make... yes (gmake) > checking for a BSD compatible install... /opt/sfw/bin/ginstall -c > checking whether ln -s works... yes > checking for ranlib... ranlib > creating ./config.status > creating Makefile > configuring in lib > running /bin/sh /export/home/local/otp_src_R9C-0/lib/configure --cache-file=.././config.cache --srcdir=/export/home/local/otp_src_R9C-0/lib > creating ./config.status > configuring in erl_interface/. > running /bin/sh /export/home/local/otp_src_R9C-0/lib/erl_interface/./configure --cache-file=../../.././config.cache --srcdir=/export/home/local/otp_src_R9C-0/lib/erl_interface/. > checking host system type... sparc-sun-solaris2.8 > checking for gcc... gcc > checking whether the C compiler (gcc ) works... yes > checking whether the C compiler (gcc ) is a cross-compiler... no > checking whether we are using GNU C... yes > checking whether gcc accepts -g... yes > checking how to run the C preprocessor... gcc -E > checking for ranlib... ranlib > checking size of short... 2 > checking size of int... 4 > checking size of long... 4 > checking size of void *... 4 > checking size of long long... 8 > checking for ar... ar > checking for a BSD compatible install... /opt/sfw/bin/ginstall -c > checking for gethostbyname in -lnsl... yes > checking for getpeername in -lsocket... yes > checking for ANSI C header files... yes > checking for sys/wait.h that is POSIX.1 compatible... yes > checking for arpa/inet.h... yes > checking for fcntl.h... yes > checking for limits.h... yes > checking for malloc.h... yes > checking for netdb.h... yes > checking for netinet/in.h... yes > checking for stddef.h... yes > checking for stdlib.h... yes > checking for string.h... yes > checking for sys/param.h... yes > checking for sys/socket.h... yes > checking for sys/time.h... yes > checking for unistd.h... yes > checking for pthread.h... yes > checking for pthread/mit/pthread.h... no > checking for uid_t in sys/types.h... yes > checking for pid_t... yes > checking for size_t... yes > checking whether time.h and sys/time.h may both be included... yes > checking for working alloca.h... yes > checking for alloca... yes > checking whether gcc needs -traditional... no > checking for 8-bit clean memcmp... yes > checking for clock_gettime... no > checking for dup2... yes > checking for gethostbyaddr... yes > checking for gethostbyname... yes > checking for gethostbyname_r... yes > checking for gethostname... yes > checking for writev... yes > checking for gethrtime... yes > checking for gettimeofday... yes > checking for inet_ntoa... yes > checking for memchr... yes > checking for memmove... yes > checking for memset... yes > checking for select... yes > checking for socket... yes > checking for strchr... yes > checking for strerror... yes > checking for strrchr... yes > checking for strstr... yes > checking for uname... yes > checking for res_gethostbyname... no > checking for res_gethostbyname in -lresolv... yes > checking if native win32 threads should be used... no > creating ./config.status > creating src/sparc-sun-solaris2.8/Makefile > creating src/sparc-sun-solaris2.8/config.h > src/sparc-sun-solaris2.8/config.h is unchanged > configuring in gs/. > running /bin/sh /export/home/local/otp_src_R9C-0/lib/gs/./configure --cache-file=../../.././config.cache --srcdir=/export/home/local/otp_src_R9C-0/lib/gs/. > checking host system type... sparc-sun-solaris2.8 > checking for prebuilt tcl/tk in tcl/binaries/sparc_solaris2.tar.gz... not found > creating ./config.status > creating tcl/sparc-sun-solaris2.8/Makefile > creating tcl/win32/Makefile > configuring in megaco/. > running /bin/sh /export/home/local/otp_src_R9C-0/lib/megaco/./configure --cache-file=../../.././config.cache --srcdir=/export/home/local/otp_src_R9C-0/lib/megaco/. > checking host system type... sparc-sun-solaris2.8 > checking for flex... flex > checking for yywrap in -lfl... no > checking for gcc... gcc > checking whether the C compiler (gcc ) works... yes > checking whether the C compiler (gcc ) is a cross-compiler... no > checking whether we are using GNU C... yes > checking whether gcc accepts -g... yes > checking for ld.sh... no > checking for ld... ld > checking for linker flags for loadable drivers... -G > checking for perl... perl > creating ./config.status > creating src/flex/sparc-sun-solaris2.8/Makefile > configuring in snmp/. > running /bin/sh /export/home/local/otp_src_R9C-0/lib/snmp/./configure --cache-file=../../.././config.cache --srcdir=/export/home/local/otp_src_R9C-0/lib/snmp/. > checking host system type... sparc-sun-solaris2.8 > checking for perl... perl > creating ./config.status > creating mibs/Makefile > configuring in erts > running /bin/sh /export/home/local/otp_src_R9C-0/erts/configure --cache-file=.././config.cache --srcdir=/export/home/local/otp_src_R9C-0/erts > loading cache .././config.cache > checking host system type... sparc-sun-solaris2.8 > checking for gcc... gcc > checking whether the C compiler (gcc ) works... yes > checking whether the C compiler (gcc ) is a cross-compiler... no > checking whether we are using GNU C... yes > checking whether gcc accepts -g... yes > checking for POSIXized ISC... no > checking for gcc... (cached) gcc > checking whether the C compiler (gcc -g -O2 ) works... yes > checking whether the C compiler (gcc -g -O2 ) is a cross-compiler... no > checking whether we are using GNU C... (cached) yes > checking whether gcc accepts -g... (cached) yes > checking for mixed cygwin and native VC++ environment... no > checking how to run the C preprocessor... gcc -E > checking for ranlib... ranlib > checking for bison... bison -y > checking for perl5... no > checking for perl... /usr/bin/perl > checking whether ln -s works... yes > checking for ar... ar > checking for a BSD compatible install... /usr/ucb/install -c > checking how to create a directory including parents... /usr/ucb/install -c -d > checking for Cygwin environment... no > checking for mingw32 environment... no > checking for executable suffix... no > checking for object suffix... o > checking for extra flags needed to export symbols... none > none > checking for sin in -lm... yes > checking for dlopen in -ldl... yes > checking for main in -linet... no > checking for main in -lresolv... yes > checking for tgetent in -lncurses... yes > checking for connect... no > checking for main in -lsocket... yes > checking for gethostbyname... no > checking for main in -lnsl... yes > checking for gethostbyname_r... yes > checking if netdb.h requires netinet/in.h to be previously included... yes > checking for getipnodebyname... yes > checking for getipnodebyaddr... yes > checking for h_errno declaration in netdb.h... yes > checking for dirent.h that defines DIR... yes > checking for opendir in -ldir... no > checking for ANSI C header files... no > checking for sys/wait.h that is POSIX.1 compatible... yes > checking whether time.h and sys/time.h may both be included... yes > checking for fcntl.h... yes > checking for limits.h... yes > checking for unistd.h... yes > checking for syslog.h... yes > checking for dlfcn.h... yes > checking for ieeefp.h... yes > checking for thread.h... yes > checking for pthread.h... yes > checking for poll.h... yes > checking for sys/stropts.h... yes > checking for sys/ioctl.h... yes > checking for sys/time.h... yes > checking for sys/uio.h... yes > checking for sys/sockio.h... yes > checking for sys/socketio.h... no > checking for net/errno.h... no > checking for malloc.h... yes > checking for mach-o/dyld.h... no > checking for arpa/nameser.h... yes > checking for pthread/mit/pthread.h... no > checking for sys/devpoll.h... yes > checking for linux/kpoll.h... no > checking for sys/event.h... no > checking for SO_BSDCOMPAT declaration... no > checking for INADDR_LOOPBACK in netinet/in.h... yes > checking for sys_errlist declaration in stdio.h or errno.h... no > checking for working const... yes > checking return type of signal handlers... void > checking for off_t... yes > checking for pid_t... yes > checking for size_t... yes > checking whether struct tm is in sys/time.h or time.h... time.h > checking whether struct sockaddr has sa_len field... no > checking for struct exception (and matherr function)... yes > checking size of short... 0 > checking size of int... 0 > checking size of long... 0 > checking size of void *... 0 > checking size of long long... 0 > checking size of size_t... 0 > checking size of off_t... 0 > checking int/long/void*/size_t sizes... failed > configure: error: Cannot handle this combination of int/long/void*/size_t sizes > configure: error: /export/home/local/otp_src_R9C-0/erts/configure failed for erts From DANIESC.SCHUTTE@REDACTED Wed Sep 10 15:42:16 2003 From: DANIESC.SCHUTTE@REDACTED (DANIESC SCHUTTE) Date: Wed, 10 Sep 2003 15:42:16 +0200 Subject: Problem's installing R9C-0 Message-ID: forgot the most important information :) : Sun Ultra 5, Solaris 8 Sparc gcc 2.95.2 >>> Raimo Niskanen 09/10/03 03:18PM >>> What kind of machine are you installing on? It seems as the configure script (using the autoconf macro AC_CHECK_SIZEOF) cannot determine the size of neither of "short, int, long, void *, long long, size_t, off_t". This means that it somehow failed to compile and run a little test program that prints "sizeof(TYPE)" to a temporary file and parse the result. Very strange. This is a standard configure script macro, they usually perform well. / Raimo Niskanen, Erlang/OTP, Ericsson AB DANIESC SCHUTTE wrote: > Morning all, > > when trying to install R9C-0 I get the following error - please check the attached install.txt file. > > Any suggestions? > > > ##################################################################################### > The information contained in this message and or attachments is intended > only for the person or entity to which it is addressed and may contain > confidential and/or privileged material. Any review, retransmission, > dissemination or other use of, or taking of any action in reliance upon, > this information by persons or entities other than the intended recipient > is prohibited. If you received this in error, please contact the sender and > delete the material from any system and destroy all copies. > ##################################################################################### > > > ------------------------------------------------------------------------ > > bash-2.03# ./configure > checking host system type... sparc-sun-solaris2.8 > checking for GNU make... yes (gmake) > checking for a BSD compatible install... /opt/sfw/bin/ginstall -c > checking whether ln -s works... yes > checking for ranlib... ranlib > creating ./config.status > creating Makefile > configuring in lib > running /bin/sh /export/home/local/otp_src_R9C-0/lib/configure --cache-file=.././config.cache --srcdir=/export/home/local/otp_src_R9C-0/lib > creating ./config.status > configuring in erl_interface/. > running /bin/sh /export/home/local/otp_src_R9C-0/lib/erl_interface/./configure --cache-file=../../.././config.cache --srcdir=/export/home/local/otp_src_R9C-0/lib/erl_interface/. > checking host system type... sparc-sun-solaris2.8 > checking for gcc... gcc > checking whether the C compiler (gcc ) works... yes > checking whether the C compiler (gcc ) is a cross-compiler... no > checking whether we are using GNU C... yes > checking whether gcc accepts -g... yes > checking how to run the C preprocessor... gcc -E > checking for ranlib... ranlib > checking size of short... 2 > checking size of int... 4 > checking size of long... 4 > checking size of void *... 4 > checking size of long long... 8 > checking for ar... ar > checking for a BSD compatible install... /opt/sfw/bin/ginstall -c > checking for gethostbyname in -lnsl... yes > checking for getpeername in -lsocket... yes > checking for ANSI C header files... yes > checking for sys/wait.h that is POSIX.1 compatible... yes > checking for arpa/inet.h... yes > checking for fcntl.h... yes > checking for limits.h... yes > checking for malloc.h... yes > checking for netdb.h... yes > checking for netinet/in.h... yes > checking for stddef.h... yes > checking for stdlib.h... yes > checking for string.h... yes > checking for sys/param.h... yes > checking for sys/socket.h... yes > checking for sys/time.h... yes > checking for unistd.h... yes > checking for pthread.h... yes > checking for pthread/mit/pthread.h... no > checking for uid_t in sys/types.h... yes > checking for pid_t... yes > checking for size_t... yes > checking whether time.h and sys/time.h may both be included... yes > checking for working alloca.h... yes > checking for alloca... yes > checking whether gcc needs -traditional... no > checking for 8-bit clean memcmp... yes > checking for clock_gettime... no > checking for dup2... yes > checking for gethostbyaddr... yes > checking for gethostbyname... yes > checking for gethostbyname_r... yes > checking for gethostname... yes > checking for writev... yes > checking for gethrtime... yes > checking for gettimeofday... yes > checking for inet_ntoa... yes > checking for memchr... yes > checking for memmove... yes > checking for memset... yes > checking for select... yes > checking for socket... yes > checking for strchr... yes > checking for strerror... yes > checking for strrchr... yes > checking for strstr... yes > checking for uname... yes > checking for res_gethostbyname... no > checking for res_gethostbyname in -lresolv... yes > checking if native win32 threads should be used... no > creating ./config.status > creating src/sparc-sun-solaris2.8/Makefile > creating src/sparc-sun-solaris2.8/config.h > src/sparc-sun-solaris2.8/config.h is unchanged > configuring in gs/. > running /bin/sh /export/home/local/otp_src_R9C-0/lib/gs/./configure --cache-file=../../.././config.cache --srcdir=/export/home/local/otp_src_R9C-0/lib/gs/. > checking host system type... sparc-sun-solaris2.8 > checking for prebuilt tcl/tk in tcl/binaries/sparc_solaris2.tar.gz... not found > creating ./config.status > creating tcl/sparc-sun-solaris2.8/Makefile > creating tcl/win32/Makefile > configuring in megaco/. > running /bin/sh /export/home/local/otp_src_R9C-0/lib/megaco/./configure --cache-file=../../.././config.cache --srcdir=/export/home/local/otp_src_R9C-0/lib/megaco/. > checking host system type... sparc-sun-solaris2.8 > checking for flex... flex > checking for yywrap in -lfl... no > checking for gcc... gcc > checking whether the C compiler (gcc ) works... yes > checking whether the C compiler (gcc ) is a cross-compiler... no > checking whether we are using GNU C... yes > checking whether gcc accepts -g... yes > checking for ld.sh... no > checking for ld... ld > checking for linker flags for loadable drivers... -G > checking for perl... perl > creating ./config.status > creating src/flex/sparc-sun-solaris2.8/Makefile > configuring in snmp/. > running /bin/sh /export/home/local/otp_src_R9C-0/lib/snmp/./configure --cache-file=../../.././config.cache --srcdir=/export/home/local/otp_src_R9C-0/lib/snmp/. > checking host system type... sparc-sun-solaris2.8 > checking for perl... perl > creating ./config.status > creating mibs/Makefile > configuring in erts > running /bin/sh /export/home/local/otp_src_R9C-0/erts/configure --cache-file=.././config.cache --srcdir=/export/home/local/otp_src_R9C-0/erts > loading cache .././config.cache > checking host system type... sparc-sun-solaris2.8 > checking for gcc... gcc > checking whether the C compiler (gcc ) works... yes > checking whether the C compiler (gcc ) is a cross-compiler... no > checking whether we are using GNU C... yes > checking whether gcc accepts -g... yes > checking for POSIXized ISC... no > checking for gcc... (cached) gcc > checking whether the C compiler (gcc -g -O2 ) works... yes > checking whether the C compiler (gcc -g -O2 ) is a cross-compiler... no > checking whether we are using GNU C... (cached) yes > checking whether gcc accepts -g... (cached) yes > checking for mixed cygwin and native VC++ environment... no > checking how to run the C preprocessor... gcc -E > checking for ranlib... ranlib > checking for bison... bison -y > checking for perl5... no > checking for perl... /usr/bin/perl > checking whether ln -s works... yes > checking for ar... ar > checking for a BSD compatible install... /usr/ucb/install -c > checking how to create a directory including parents... /usr/ucb/install -c -d > checking for Cygwin environment... no > checking for mingw32 environment... no > checking for executable suffix... no > checking for object suffix... o > checking for extra flags needed to export symbols... none > none > checking for sin in -lm... yes > checking for dlopen in -ldl... yes > checking for main in -linet... no > checking for main in -lresolv... yes > checking for tgetent in -lncurses... yes > checking for connect... no > checking for main in -lsocket... yes > checking for gethostbyname... no > checking for main in -lnsl... yes > checking for gethostbyname_r... yes > checking if netdb.h requires netinet/in.h to be previously included... yes > checking for getipnodebyname... yes > checking for getipnodebyaddr... yes > checking for h_errno declaration in netdb.h... yes > checking for dirent.h that defines DIR... yes > checking for opendir in -ldir... no > checking for ANSI C header files... no > checking for sys/wait.h that is POSIX.1 compatible... yes > checking whether time.h and sys/time.h may both be included... yes > checking for fcntl.h... yes > checking for limits.h... yes > checking for unistd.h... yes > checking for syslog.h... yes > checking for dlfcn.h... yes > checking for ieeefp.h... yes > checking for thread.h... yes > checking for pthread.h... yes > checking for poll.h... yes > checking for sys/stropts.h... yes > checking for sys/ioctl.h... yes > checking for sys/time.h... yes > checking for sys/uio.h... yes > checking for sys/sockio.h... yes > checking for sys/socketio.h... no > checking for net/errno.h... no > checking for malloc.h... yes > checking for mach-o/dyld.h... no > checking for arpa/nameser.h... yes > checking for pthread/mit/pthread.h... no > checking for sys/devpoll.h... yes > checking for linux/kpoll.h... no > checking for sys/event.h... no > checking for SO_BSDCOMPAT declaration... no > checking for INADDR_LOOPBACK in netinet/in.h... yes > checking for sys_errlist declaration in stdio.h or errno.h... no > checking for working const... yes > checking return type of signal handlers... void > checking for off_t... yes > checking for pid_t... yes > checking for size_t... yes > checking whether struct tm is in sys/time.h or time.h... time.h > checking whether struct sockaddr has sa_len field... no > checking for struct exception (and matherr function)... yes > checking size of short... 0 > checking size of int... 0 > checking size of long... 0 > checking size of void *... 0 > checking size of long long... 0 > checking size of size_t... 0 > checking size of off_t... 0 > checking int/long/void*/size_t sizes... failed > configure: error: Cannot handle this combination of int/long/void*/size_t sizes > configure: error: /export/home/local/otp_src_R9C-0/erts/configure failed for erts ##################################################################################### The information contained in this message and or attachments is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any system and destroy all copies. ##################################################################################### From vlad_dumitrescu@REDACTED Wed Sep 10 16:07:58 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Wed, 10 Sep 2003 16:07:58 +0200 Subject: Wither Self References: <200309100219.h8A2J79V362642@atlas.otago.ac.nz> Message-ID: From: "Richard A. O'Keefe" > I presume that Joe's reason for wanting this is to handle the quite > common case where you need a recursive function that can refer to a > local variable. Yes, of course. > In short, there are cases where locally defined recursive functions > are harder to read than the alternatives, and, based on Haskell and > ML experience, there are cases where they are much easier to read than > the alternatives. I guess I am biased by some real-life examples I met, where the inlined function was a real monster and should have been split in 2 or maybe 3 different simpler functions, the result still being easier to read than the original. Think just of 20 lines with an indentation of 50+ chars... *brrr* regards, Vlad From mlogan@REDACTED Wed Sep 10 17:34:35 2003 From: mlogan@REDACTED (Martin J. Logan) Date: 10 Sep 2003 10:34:35 -0500 Subject: Doc or gen_event:notify/2 Error! In-Reply-To: <3F5EBFDC.BD01317C@erix.ericsson.se> References: <1063145556.2708.32.camel@dhcp-lom-194-186.futuresource.com> <3F5EBFDC.BD01317C@erix.ericsson.se> Message-ID: <1063208075.2708.49.camel@dhcp-lom-194-186.futuresource.com> I will catch the error then. I think that having to take measures to avoid a crash produced by my asynchronous call seems to run counter to the spirit of asynchronous communication. Though I could be missing some overriding reason to let it exit. On Wed, 2003-09-10 at 01:08, Gunilla Arendt wrote: > Snip from the gen_event man page: > > "Unless otherwise stated, all functions in this module fail > if the specified event manager does not exist or if bad > arguments are given" > > The same goes for gen_server and gen_fsm. > > Regards, Gunilla > > "Martin J. Logan" wrote: > > > > Hello, > > I have found an inconsistency in the docs. > > > > The docs indicate that the return value for gen_event notify is as > > follows: > > > > notify(EventMgrRef, Event) -> ok > > > > This makes sense as it is asynchronous. I pass a registered name to a > > notify call and if the name is not registered I get an exit(). It is the > > same badarg exit that one would expect from > > > > unregistered_name ! message > > > > I think that either the docs should be changed to > > > > notify(EventMgrRef, Event) -> ok | exit() > > > > or more preferably the notify/2 function should not exit. > > > > Cheers, > > Martin > > > > OUTPUT: > > > > gen_event:notify(martin, martin). > > > > =ERROR REPORT==== 9-Sep-2003::17:05:56 === > > Error in process <0.31.0> with exit value: > > {badarg,[{gen_event,send,2},{erl_eval,do_apply,5},{shell,eval_loop,2}]} > > > > ** exited: {badarg,[{gen_event,send,2}, > > {erl_eval,do_apply,5}, > > {shell,eval_loop,2}]} ** From Zoltan.Toth@REDACTED Wed Sep 10 17:43:32 2003 From: Zoltan.Toth@REDACTED (Zoltan Peter Toth) Date: Wed, 10 Sep 2003 17:43:32 +0200 Subject: Memory handling description? Message-ID: <3F5F46A4.2010106@eth.ericsson.se> Hi folks, Can anybody give me a reference to some technical document that outlines how memory handling (heap, variable storage, message passing, etc) is done in the Erlang machine ? (e.g. when is memory allocated, released, etc.) Thanks, Zoltan From lennart.ohman@REDACTED Wed Sep 10 17:51:12 2003 From: lennart.ohman@REDACTED (=?ISO-8859-1?Q?Lennart_=D6hman?=) Date: Wed, 10 Sep 2003 17:51:12 +0200 Subject: Doc or gen_event:notify/2 Error! In-Reply-To: <1063208075.2708.49.camel@dhcp-lom-194-186.futuresource.com> References: <1063145556.2708.32.camel@dhcp-lom-194-186.futuresource.com> <3F5EBFDC.BD01317C@erix.ericsson.se> <1063208075.2708.49.camel@dhcp-lom-194-186.futuresource.com> Message-ID: <3F5F4870.1020500@st.se> Hi, not claiming to have the perfect answer or solution but. Many other OTP client/server functions crash if something goes wrong. For instance if you have a time-out on a call. Then there is already a difference in the behaviour in Erlang between sending to a non existing PID and a non existing name. The first is legal but the second causes a run-time error. One can then argue that the call function shall follow this anomaly since it is what an Erlang programmer may expect. /Lennart Martin J. Logan wrote: > I will catch the error then. I think that having to take measures to > avoid a crash produced by my asynchronous call seems to run counter to > the spirit of asynchronous communication. Though I could be missing some > overriding reason to let it exit. > > > On Wed, 2003-09-10 at 01:08, Gunilla Arendt wrote: > >>Snip from the gen_event man page: >> >>"Unless otherwise stated, all functions in this module fail >> if the specified event manager does not exist or if bad >> arguments are given" >> >>The same goes for gen_server and gen_fsm. >> >>Regards, Gunilla >> >>"Martin J. Logan" wrote: >> >>>Hello, >>> I have found an inconsistency in the docs. >>> >>>The docs indicate that the return value for gen_event notify is as >>>follows: >>> >>>notify(EventMgrRef, Event) -> ok >>> >>>This makes sense as it is asynchronous. I pass a registered name to a >>>notify call and if the name is not registered I get an exit(). It is the >>>same badarg exit that one would expect from >>> >>>unregistered_name ! message >>> >>>I think that either the docs should be changed to >>> >>>notify(EventMgrRef, Event) -> ok | exit() >>> >>>or more preferably the notify/2 function should not exit. >>> >>>Cheers, >>>Martin >>> >>>OUTPUT: >>> >>>gen_event:notify(martin, martin). >>> >>>=ERROR REPORT==== 9-Sep-2003::17:05:56 === >>>Error in process <0.31.0> with exit value: >>>{badarg,[{gen_event,send,2},{erl_eval,do_apply,5},{shell,eval_loop,2}]} >>> >>>** exited: {badarg,[{gen_event,send,2}, >>> {erl_eval,do_apply,5}, >>> {shell,eval_loop,2}]} ** > > -- ------------------------------------------------------------- Lennart Ohman phone : +46-8-587 623 27 Sjoland & Thyselius Telecom AB cellular: +46-70-552 6735 Sehlstedtsgatan 6 fax : +46-8-667 8230 SE-115 28 STOCKHOLM, SWEDEN email : lennart.ohman@REDACTED From cpressey@REDACTED Wed Sep 10 18:35:37 2003 From: cpressey@REDACTED (Chris Pressey) Date: Wed, 10 Sep 2003 09:35:37 -0700 Subject: Wither Self (longish) In-Reply-To: References: <200309100219.h8A2J79V362642@atlas.otago.ac.nz> Message-ID: <20030910093537.0f81e414.cpressey@catseye.mine.nu> On Wed, 10 Sep 2003 16:07:58 +0200 "Vlad Dumitrescu" wrote: > I guess I am biased by some real-life examples I met, where the > inlined function was a real monster and should have been split in 2 or > maybe 3 different simpler functions, the result still being easier to > read than the original. Think just of 20 lines with an indentation of > 50+ chars... *brrr* Having been the author of some funs like this, I concur. But there is a tradeoff - in my case, I have a function that creates a lot of callback functions (for GTK.) The easiest way to get certain parameters to those callback functions is to have the callbacks be declared as funs so that they can access the bindings in the main function. The other way to do it would be to pass those bindings as parameters - the GTK callbacks certainly allow this, but after trying it, my judgement call was that it was even messier that way. So I stuck with a really long main function with lots of embedded funs - and this is where SciTE (the folding editor that groks Erlang syntax) has really helped. There are of course more ways to deal with it. For example, factor everything that doesn't need to inherit bindings out of the fun, into utility functions. But my needs have become even more involved lately, which is why I'm currently pondering lambda modules and their alternatives. (I've foregone considering hot code replacement on them because it's just too damn hard, if it's indeed possible.) My 'problem' is this. Behaviours are a great way to structure your code. But the more behaviours and callback modules I write, the simpler I tend to make them, to the point where the callback contains mostly data and hardly any code. This certainly seems like good engineering - the behaviour does most of the work (making it 'reusable', etc) while the callback mainly tells the behaviour how, specifically, it should do the work. But then I get to the point where I'd like to make tiny alterations in a callback module, *from my code*. And the callback modules are simple enough, at this point, that they *could* just be data structures. Unfortunately, if I convert the callback module to a data structure, many nice things can disappear. Essentially, all the callbacks which aren't just plain data, have to become funs, and this introduces some inconveniences that look minor, but can be very annoying. For example, calls that were once sweet and simple like M:f(A1, A2) now have to become something like dict:fetch(f, M)(A1, A2) and so on. Initially it looked like a great advantage would be that I could store these 'callback modules' in file:consult/1 format - but file:consult/1 doesn't allow for funs, so I wrote a version of it that does (I've attached it to this e-mail for the sake of curiousity.) All in all it's a slight win, because I can now manipulate and transform the callback 'module', in my code - but it's only a *slight* win, because the structure is now not nearly as nice as it was when it was a genuine behaviour-conforming callback module. Anyway - that's been my experience so far. I'd like to figure out a way for it to be a big win, or at least a medium-sized win, instead, but I think it'll mean getting in up to my elbows in parsing and evaluating Erlang code, and maybe even a parse transform to handle M:f(A) when M is not a 'real' module - which sounds like more trouble than it's worth... -Chris -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: consult.erl URL: From mlogan@REDACTED Wed Sep 10 18:45:47 2003 From: mlogan@REDACTED (Martin J. Logan) Date: 10 Sep 2003 11:45:47 -0500 Subject: Doc or gen_event:notify/2 Error! In-Reply-To: <3F5F4870.1020500@st.se> References: <1063145556.2708.32.camel@dhcp-lom-194-186.futuresource.com> <3F5EBFDC.BD01317C@erix.ericsson.se> <1063208075.2708.49.camel@dhcp-lom-194-186.futuresource.com> <3F5F4870.1020500@st.se> Message-ID: <1063212347.2708.97.camel@dhcp-lom-194-186.futuresource.com> I think that a "call" should crash if there is a timeout - let it die unless you catch the error for some reason. Calls with a timeout are necessarily synchronous. I am just wondering if asynchronous casts and messages should have the same behaviour. Should an unregistered_name ! msg really cause an exit? Is this something to "let it die" over? Is not the true spirit of asynchronous messaging just send and pray? Martin On Wed, 2003-09-10 at 10:51, Lennart ?hman wrote: > Hi, > not claiming to have the perfect answer or solution but. Many other > OTP client/server functions crash if something goes wrong. For instance > if you have a time-out on a call. > > Then there is already a difference in the behaviour in Erlang between > sending to a non existing PID and a non existing name. The first is > legal but the second causes a run-time error. One can then argue that > the call function shall follow this anomaly since it is what an Erlang > programmer may expect. > > /Lennart > > Martin J. Logan wrote: > > > I will catch the error then. I think that having to take measures to > > avoid a crash produced by my asynchronous call seems to run counter to > > the spirit of asynchronous communication. Though I could be missing some > > overriding reason to let it exit. > > > > > > On Wed, 2003-09-10 at 01:08, Gunilla Arendt wrote: > > > >>Snip from the gen_event man page: > >> > >>"Unless otherwise stated, all functions in this module fail > >> if the specified event manager does not exist or if bad > >> arguments are given" > >> > >>The same goes for gen_server and gen_fsm. > >> > >>Regards, Gunilla > >> > >>"Martin J. Logan" wrote: > >> > >>>Hello, > >>> I have found an inconsistency in the docs. > >>> > >>>The docs indicate that the return value for gen_event notify is as > >>>follows: > >>> > >>>notify(EventMgrRef, Event) -> ok > >>> > >>>This makes sense as it is asynchronous. I pass a registered name to a > >>>notify call and if the name is not registered I get an exit(). It is the > >>>same badarg exit that one would expect from > >>> > >>>unregistered_name ! message > >>> > >>>I think that either the docs should be changed to > >>> > >>>notify(EventMgrRef, Event) -> ok | exit() > >>> > >>>or more preferably the notify/2 function should not exit. > >>> > >>>Cheers, > >>>Martin > >>> > >>>OUTPUT: > >>> > >>>gen_event:notify(martin, martin). > >>> > >>>=ERROR REPORT==== 9-Sep-2003::17:05:56 === > >>>Error in process <0.31.0> with exit value: > >>>{badarg,[{gen_event,send,2},{erl_eval,do_apply,5},{shell,eval_loop,2}]} > >>> > >>>** exited: {badarg,[{gen_event,send,2}, > >>> {erl_eval,do_apply,5}, > >>> {shell,eval_loop,2}]} ** > > > > From richardc@REDACTED Wed Sep 10 18:51:40 2003 From: richardc@REDACTED (Richard Carlsson) Date: Wed, 10 Sep 2003 18:51:40 +0200 (MET DST) Subject: Wither Self (shortish) In-Reply-To: <20030910093537.0f81e414.cpressey@catseye.mine.nu> References: <200309100219.h8A2J79V362642@atlas.otago.ac.nz> <20030910093537.0f81e414.cpressey@catseye.mine.nu> Message-ID: On Wed, 10 Sep 2003, Chris Pressey wrote: > There are of course more ways to deal with it. For example, factor > everything that doesn't need to inherit bindings out of the fun, into > utility functions. Here's a nice way of combining funs and factoring: f(A,B,C) -> ... F = fun (X, Y) -> h(X, Y, A, B, C) end, do_stuff(F). h(X, Y, A, B, C) -> ... do_stuff(F) -> P = ..., Q = ..., F(P, Q). This way, the fun F has the right arity for the job (2, in this case), and still carries all the extra info it needs (A, B, and C), but you don't have to put all the code for the fun at the place where you define it. Don't know if this helps you, though. I tend to use this pattern when I spawn processes: f(A, B, C) -> Parent = self(), Pid = spawn(fun () -> process(Parent, A, B, C) end), ... process(Parent, A, B, C) -> ... /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ "Having users is like optimization: the wise course is to delay it." -- Paul Graham From pjdurai@REDACTED Wed Sep 10 18:21:09 2003 From: pjdurai@REDACTED (pj) Date: Wed, 10 Sep 2003 10:21:09 -0600 Subject: Erlang FFI question Message-ID: Greetings. I am new to erlang. From what I have learned (Online Erlang book, and some random tutorials from Net) its very impressive. I would like to learn about how to interface C libraris and Dll's from erlang. What is the preferred method of talking to the 'out side world' ? I (vaguely) saw some method of spawning a native application and talk to it with something called 'Ports'. Is that the way to do it? How about calling shared libraries and dlls? I believe corba is an option. Does win32 erlang do COM ? Appreciate your time. thanks pj From luke@REDACTED Wed Sep 10 19:56:14 2003 From: luke@REDACTED (Luke Gorrie) Date: 10 Sep 2003 19:56:14 +0200 Subject: Wither Self In-Reply-To: References: <200309100219.h8A2J79V362642@atlas.otago.ac.nz> Message-ID: "Vlad Dumitrescu" writes: > > In short, there are cases where locally defined recursive functions > > are harder to read than the alternatives, and, based on Haskell and > > ML experience, there are cases where they are much easier to read than > > the alternatives. > > I guess I am biased by some real-life examples I met, where the > inlined function was a real monster and should have been split in 2 > or maybe 3 different simpler functions, the result still being > easier to read than the original. Think just of 20 lines with an > indentation of 50+ chars... *brrr* IMO it's the indentation that is the biggest problem! I often avoid using funs because they would push me over 80 columns. We were discussing this over beer after the Erlang Workshop. Who's in favour of hacking the Erlang indentation rules (i.e. Emacs mode) to reduce indentation in funs? Example: OLD: fun(X) -> foo(X) end. NEW: fun(X) -> foo(X) end. OLD: fun(X) when integer(X); list(X) -> foo(X); (Y) -> bar(X) end. NEW: fun(X) when integer(X); list(X) -> foo(X); (Y) -> bar(X) end. Anything obvious I've missed? Any objections? Cheers, Luke From lennart.ohman@REDACTED Wed Sep 10 21:10:26 2003 From: lennart.ohman@REDACTED (=?UTF-8?B?TGVubmFydCDDlmhtYW4=?=) Date: Wed, 10 Sep 2003 21:10:26 +0200 Subject: Doc or gen_event:notify/2 Error! In-Reply-To: <1063212347.2708.97.camel@dhcp-lom-194-186.futuresource.com> References: <1063145556.2708.32.camel@dhcp-lom-194-186.futuresource.com> <3F5EBFDC.BD01317C@erix.ericsson.se> <1063208075.2708.49.camel@dhcp-lom-194-186.futuresource.com> <3F5F4870.1020500@st.se> <1063212347.2708.97.camel@dhcp-lom-194-186.futuresource.com> Message-ID: <3F5F7722.6090407@st.se> > ... > messages should have the same behaviour. Should an unregistered_name ! > msg really cause an exit? Is this something to "let it die" over? Is not > ... I did not say this is a perfect semantics. Only that *having* this semantics may imply that both cast and call should work in the same manner! :-) /Lennart ------------------------------------------------------------- Lennart Ohman phone : +46-8-587 623 27 Sjoland & Thyselius Telecom AB cellular: +46-70-552 6735 Sehlstedtsgatan 6 fax : +46-8-667 8230 SE-115 28 STOCKHOLM, SWEDEN email : lennart.ohman@REDACTED From vlad_dumitrescu@REDACTED Wed Sep 10 21:23:21 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Wed, 10 Sep 2003 21:23:21 +0200 Subject: ODBC connection fails Message-ID: Hello, I'm trying my luck with ODBC, and I can't make it work from Erlang. I am running WinXP, OTP R9C out-of-the-box, and Firebird as a database. I used some other tools to test the ODBC connection and they work. This is my output: (vlad@REDACTED)4> A=odbc:connect("DSN=vlad_test;UID=sysdba;PWD=masterkey",[{tr ace_driver,on}]). {error,connection_closed} =ERROR REPORT==== 10-Sep-2003::21:14:24 === ** Generic server <0.66.0> terminating ** Last message in was {#Port<0.61>,{exit_status,1}} ** When Server state == {state,#Port<0.61>, undefined, <0.64.0>, undefined, on, undefined, undefined, on, connecting, undefined, 0, false, false, []} ** Reason for termination == ** {badarg,[{erlang,port_close,[#Port<0.61>]}, {odbc,terminate,2}, {gen_server,terminate,6}, {proc_lib,init_p,5}]} I am thankful for any suggestions about the cause of this. best regards, Vlad From per@REDACTED Wed Sep 10 22:34:51 2003 From: per@REDACTED (Per Hedeland) Date: Wed, 10 Sep 2003 22:34:51 +0200 (CEST) Subject: Problem's installing R9C-0 In-Reply-To: Message-ID: <200309102034.h8AKYpQH029675@tordmule.bluetail.com> "DANIESC SCHUTTE" wrote: > >Sun Ultra 5, Solaris 8 Sparc >gcc 2.95.2 Hm, sounds like an install of the "optional software" CD (or whatever it's called) that comes with the OS - right? I happen to have such a box here - yup, I can reproduce your problem. >>>> Raimo Niskanen 09/10/03 03:18PM >>> >What kind of machine are you installing on? > >It seems as the configure script (using the autoconf macro >AC_CHECK_SIZEOF) cannot determine the size of neither of "short, int, >long, void *, long long, size_t, off_t". This means that it somehow >failed to compile and run a little test program that prints >"sizeof(TYPE)" to a temporary file and parse the result. > >Very strange. This is a standard configure script macro, they usually >perform well. Even stranger is that erl_interface's configure script (run earlier) had no problem doing the same thing (maybe the result should be cached:-). Anyway, this seems to be a case of "broken gcc installation" - I haven't tried it with a "proper" one on Solaris 8, but I assume that you have.:-) Configure *usually* works well, but it's also notorious for drawing altogether the wrong conclusions when its tests fail in "unexpected" ways - usually config.log tells the real story in those cases, but here even that was basically silent, just said that the test program "failed" w/o giving any error messages. So we have to try to reproduce what it did (this is the "sizeof short" test): $ gcc -o conftest -g -O2 -I/var/tmp/otp_src_R9C-0/erts/sparc-sun-solaris2.8 conftest.c -lncurses -lresolv -ldl -lm -lsocket -lnsl $ ./conftest ld.so.1: ./conftest: fatal: libncurses.so.5: open failed: No such file or directory Killed I.e. what is happening is that libncurses is found at compile time but not at run time, which on Solaris typically means that you used -L to point to some non-standard directory, but not the corresponding -R to point the runtime linker to the same place. And this is what this *gcc installation* does - adding -v to the options above reveals that it passes -L/opt/sfw/lib to 'ld' (but no -R), and that is indeed where libncurses is found. Per above, I'd recommend a reinstall of gcc (e.g. build from source), but it's possible to work around by hack^H^H^H^Husing LD_LIBRARY_PATH: $ env LD_LIBRARY_PATH=/opt/sfw/lib ./conftest $ cat conftestval 2 Doing the build this way means that you will have to use the same method also when running the system, though. Alternatively you can read crle(1) and apply. --Per From james@REDACTED Thu Sep 11 04:14:19 2003 From: james@REDACTED (James Hague) Date: Wed, 10 Sep 2003 21:14:19 -0500 Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: References: <3F5B6E51.16454.289DB0@localhost> Message-ID: <3F5F942B.23382.140008@localhost> Luke Gorrie wrote: > > Have you considered using existing mid-level languages instead? If so, > are there any that seem particularly qualified/disqualified? I'm partial to both Forth and Lisp, but newer, optimizing Forth systems tend to be a bit eclectic, and I haven't found a good, machine code generating Lisp system that's cross-platform. The Windows port of CMUCL is apparently stalled. I suspect the easiest option, or the one I'd have the most fun writing, would be a homebrew Forth. An interesting option is C-- (see cminusminus.org). James From cpressey@REDACTED Thu Sep 11 06:44:26 2003 From: cpressey@REDACTED (Chris Pressey) Date: Wed, 10 Sep 2003 21:44:26 -0700 Subject: Wither Self (shortish) In-Reply-To: References: <200309100219.h8A2J79V362642@atlas.otago.ac.nz> <20030910093537.0f81e414.cpressey@catseye.mine.nu> Message-ID: <20030910214426.78e9ff66.cpressey@catseye.mine.nu> On Wed, 10 Sep 2003 18:51:40 +0200 (MET DST) Richard Carlsson wrote: > Here's a nice way of combining funs and factoring: > > f(A,B,C) -> > ... > F = fun (X, Y) -> h(X, Y, A, B, C) end, > do_stuff(F). > > h(X, Y, A, B, C) -> > ... > > do_stuff(F) -> > P = ..., > Q = ..., > F(P, Q). > > This way, the fun F has the right arity for the job (2, in this > case), and still carries all the extra info it needs (A, B, and C), > but you don't have to put all the code for the fun at the place > where you define it. > > Don't know if this helps you, though. It's a nice technique, but no, it doesn't really help me here. The first issue is that I am very strongly against short (cryptic!) names. (I suppose that might make me a minority in Erlang circles, but after working on certain legacy source code with variables with names like O1I1K in it, no amount of peer pressure could make me reconsider my stance :) So instead of h(X, Y, A, B, C) I would have something more like button_pressed(Button, Window, CList, ProgressBar, FileOptions) That's bad enough; but the second issue is that, every time I have to pass another parameter or a different parameter to the callback, I would have to change the parameter list in *two* places in the source, compared to zero with just the fun. So all in all I just don't feel it's worth it in this case. > I tend to use this pattern > when I spawn processes: > > f(A, B, C) -> > Parent = self(), > Pid = spawn(fun () -> process(Parent, A, B, C) end), > ... > > process(Parent, A, B, C) -> > ... I usually do that these days, too, to save the export declaration; although IIRC the first time I tried it (I think it was with GTK), it didn't work at all, so I was slow to adopt it after that. -Chris From cpressey@REDACTED Thu Sep 11 07:00:06 2003 From: cpressey@REDACTED (Chris Pressey) Date: Wed, 10 Sep 2003 22:00:06 -0700 Subject: Erlang FFI question In-Reply-To: References: Message-ID: <20030910220006.0010ba3c.cpressey@catseye.mine.nu> On Wed, 10 Sep 2003 10:21:09 -0600 "pj" wrote: > Greetings. > > I am new to erlang. From what I have learned (Online Erlang book, and > some random tutorials from Net) its very impressive. > > I would like to learn about how to interface C libraris and Dll's from > erlang. > What is the preferred method of talking to the 'out side world' ? > > I (vaguely) saw some method of spawning a native application and talk > to it with something called 'Ports'. Is that the way to do it? How > about calling shared libraries and dlls? Hi PJ, There are many methods. This document explains most of them: http://www.erlang.org/doc/r9c/doc/tutorial/part_frame.html Study it, try compiling the example programs in it, and you should get a good feel for what the preferred methods are in various circumstances. > I believe corba is an option. Yes. > Does win32 erlang do COM ? It appears that it used to: http://www.erlang.se/doc/doc-5.0.1/lib/comet-1.0/doc/ but I don't think that COMET is supported anymore - I can't find it in R9C (the latest release.) -Chris From D.WILLIAMS@REDACTED Thu Sep 11 09:02:37 2003 From: D.WILLIAMS@REDACTED (WILLIAMS Dominic) Date: Thu, 11 Sep 2003 09:02:37 +0200 Subject: Wither Self Message-ID: > From: Luke Gorrie > > We were discussing this over beer after the Erlang Workshop. Who's in > favour of hacking the Erlang indentation rules (i.e. Emacs mode) to > reduce indentation in funs? I am in favour of being given the possibility (as with ccmode) to customize the indentation. But if this is complicated, I am still in favour of reducing the Emacs mode's indentation, especially for funs, but also in other cases (basically I disapprove of aligning with something in the previous line, I prefer a fixed 3 or 4 spaces indentation.) Regards, Dominic. From ulf.wiger@REDACTED Thu Sep 11 09:32:46 2003 From: ulf.wiger@REDACTED (=?utf-8?B?VWxmIFdpZ2VyICjDhEwyL0VBQik=?=) Date: Thu, 11 Sep 2003 09:32:46 +0200 Subject: Doc or gen_event:notify/2 Error! Message-ID: <76E5F712842F5F49A35738622BAA0F4F9EA705@ESEALNT442.al.sw.ericsson.se> From: Martin J. Logan [mailto:mlogan@REDACTED] > Calls with a timeout are necessarily synchronous. I am just > wondering if asynchronous casts and messages should have the > same behaviour. Should an unregistered_name ! msg really cause > an exit? Is this something to "let it die" over? Is not > the true spirit of asynchronous messaging just send and pray? Actually, an earlier OTP release changed this behaviour, so that RegName ! msg had the same semantics as Pid ! msg. This was more consistent, but could cause some really nasty bugs in legacy code. The behaviour was then reversed, and the discussions triggered by the whole thing eventually led to the introduction of the monitor() BIF.(*) /Uffe (*) This step may not be obvious. One of the important uses of RegName ! Msg was to get early detection in the most common cases where the process at the other end were down. This was not a watertight solution, but improved the behaviour overall. The problem to be solved was how to do reliable detection of such faults in a synchronous dialogue without always having to rely on the timeout (which has to be dimensioned for the worst "legal" case in order to avoid false timeouts.) Timeouts were needed, but not the whole solution. Links were two-way (not what we wanted), and not stackable (difficult to know when to unlink). Enter monitor(), which is one-way and stackable, so that we can turn it on locally in e.g. a gen:call() without disturbing anything else, and getting reliable early detection if the other process fails. From Bengt.Kleberg@REDACTED Thu Sep 11 10:08:33 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Thu, 11 Sep 2003 10:08:33 +0200 Subject: Wither Self In-Reply-To: References: Message-ID: <3F602D81.7070300@ericsson.com> WILLIAMS Dominic wrote: ...deleted > I am in favour of being given the possibility (as with ccmode) to customize > the indentation. would it not be nice to have ''indent'' for erlang? > (basically I disapprove of aligning with something in the previous line, I > prefer a fixed 3 or 4 spaces indentation.) actually it is even better with a fixed tab indention. set TABSTOP to 2,3,4... spaces and anyone can have their prefered number of spaces. bengt From erlang@REDACTED Thu Sep 11 10:47:38 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Thu, 11 Sep 2003 09:47:38 +0100 Subject: Wither Self In-Reply-To: <3F602D81.7070300@ericsson.com> References: <3F602D81.7070300@ericsson.com> Message-ID: <3F6036AA.5080509@manderp.freeserve.co.uk> Hi Gurus, Ahem! I sense Yet Another Religious Nitpick or YARN(TM) over tabs vs. space and indentation columns. Please stop, it won't lead anywhere useful! "Erlindent" would keep the peace only if it were capable of reformatting code in any way the operator desires, *without* emacs, including switching spaces for tabs and vice versa. It would allow each of us to write in any style we prefer, and convert other people's style into our own prefered style. I would like to preserve everyone's freedom to write as they please. The next debate may be over good comment writing practice... anyone got a comment stripper for Erlang? (-: Pete. Bengt Kleberg wrote: > WILLIAMS Dominic wrote: > ...deleted > >> I am in favour of being given the possibility (as with ccmode) to >> customize >> the indentation. > > > would it not be nice to have ''indent'' for erlang? > > >> (basically I disapprove of aligning with something in the previous >> line, I >> prefer a fixed 3 or 4 spaces indentation.) > > > actually it is even better with a fixed tab indention. set TABSTOP to > 2,3,4... spaces and anyone can have their prefered number of spaces. > > > bengt > > > From vlad_dumitrescu@REDACTED Thu Sep 11 10:55:14 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Thu, 11 Sep 2003 10:55:14 +0200 Subject: ODBC connection fails References: Message-ID: I've found the problem... After trying even with an Oracle database, I discovered that scrollable cursors are not supported by the drivers in either case. Should there be a crash when this happens? An error message would be more appropriate here, I think, if not for other reason than to conform to the documentation :-) regards, Vlad From DANIESC.SCHUTTE@REDACTED Thu Sep 11 11:03:32 2003 From: DANIESC.SCHUTTE@REDACTED (DANIESC SCHUTTE) Date: Thu, 11 Sep 2003 11:03:32 +0200 Subject: Install R9C-0 Solaris 9 x86 Message-ID: Morning all, On a Sun VX65, Solaris 9 x86 gcc 3.3 for solaris When I configure with HIPE enabled (default) - I get the error below, however it works fine when I disable the HIPE compile. Any suggestions? (What package requirements does R9C-0 have for HIPE)? gcc -g -O3 -I/usr/local/otp_src_R9C-0/erts/i386-pc-solaris2.9 -DSHARED_HEAP -DHAVE_CONFIG_H -Wall -Wstrict-prototypes -Wmissing-prototypes -DHIPE_ARCHITECTURE=x86 -Ibeam -Isys/unix -Isys/common -Ii386-pc-solaris2.9 -Ii386-pc-solaris2.9/shared -Izlib -Ihipe -c hipe/hipe_mode_switch.c -o /usr/local/otp_src_R9C-0/erts/obj.shared.beam/i386-pc-solaris2.9/hipe_mode_switch.o gcc -g -O3 -I/usr/local/otp_src_R9C-0/erts/i386-pc-solaris2.9 -DSHARED_HEAP -DHAVE_CONFIG_H -Wall -Wstrict-prototypes -Wmissing-prototypes -DHIPE_ARCHITECTURE=x86 -Ibeam -Isys/unix -Isys/common -Ii386-pc-solaris2.9 -Ii386-pc-solaris2.9/shared -Izlib -Ihipe -c hipe/hipe_native_bif.c -o /usr/local/otp_src_R9C-0/erts/obj.shared.beam/i386-pc-solaris2.9/hipe_native_bif.o gcc -g -O2 -I/usr/local/otp_src_R9C-0/erts/i386-pc-solaris2.9 -DSHARED_HEAP -DHAVE_CONFIG_H -Wall -Wstrict-prototypes -Wmissing-prototypes -DHIPE_ARCHITECTURE=x86 -Ibeam -Isys/unix -Isys/common -Ii386-pc-solaris2.9 -Ii386-pc-solaris2.9/shared -Izlib -Ihipe -c hipe/hipe_x86_glue.S -o /usr/local/otp_src_R9C-0/erts/obj.shared.beam/i386-pc-solaris2.9/hipe_x86_glue.o Assembler: "", line 1 : Warning: Illegal flag (-) - ignored "", line 1 : Warning: Illegal flag (g) - ignored "", line 1 : Warning: Illegal flag (t) - ignored "", line 1 : Warning: Illegal flag (a) - ignored "/var/tmp//ccUYAgVX.s", line 1 : Syntax error "/var/tmp//ccUYAgVX.s", line 8 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 8 : Syntax error "/var/tmp//ccUYAgVX.s", line 8 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 9 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 9 : Syntax error "/var/tmp//ccUYAgVX.s", line 9 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 32 : Syntax error "/var/tmp//ccUYAgVX.s", line 43 : Syntax error "/var/tmp//ccUYAgVX.s", line 45 : Syntax error "/var/tmp//ccUYAgVX.s", line 49 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 49 : Syntax error "/var/tmp//ccUYAgVX.s", line 49 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 55 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 55 : Syntax error "/var/tmp//ccUYAgVX.s", line 55 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 68 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 68 : Syntax error "/var/tmp//ccUYAgVX.s", line 68 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 81 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 81 : Syntax error "/var/tmp//ccUYAgVX.s", line 81 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 93 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 93 : Syntax error "/var/tmp//ccUYAgVX.s", line 93 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 106 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 106 : Syntax error "/var/tmp//ccUYAgVX.s", line 106 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 115 : Illegal mnemonic "/var/tmp//ccUYAgVX.s", line 115 : Syntax error "/var/tmp//ccUYAgVX.s", line 115 : Illegal mnemonic Too many errors - Goodbye gmake[3]: *** [/usr/local/otp_src_R9C-0/erts/obj.shared.beam/i386-pc-solaris2.9/hipe_x86_glue.o] Error 1 gmake[3]: Leaving directory `/usr/local/otp_src_R9C-0/erts/emulator' gmake[2]: *** [shared] Error 2 gmake[2]: Leaving directory `/usr/local/otp_src_R9C-0/erts/emulator' gmake[1]: *** [shared] Error 2 gmake[1]: Leaving directory `/usr/local/otp_src_R9C-0/erts' gmake: *** [emulator] Error 2 ##################################################################################### The information contained in this message and or attachments is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any system and destroy all copies. ##################################################################################### From joe@REDACTED Thu Sep 11 11:33:17 2003 From: joe@REDACTED (Joe Armstrong) Date: Thu, 11 Sep 2003 11:33:17 +0200 (CEST) Subject: format error In-Reply-To: Message-ID: Hi, I tried to reproduce your problem but failed, some of the lines you omitted might be relevant to your problem. Can you post a short complete module that reproduces the problem? Even if you don't intend to upgrade to the "latest version" of OTP (you may have good reasons not to do this) you could possibly compile up the latest version of OTP and see if the error manifests itself in the new system. Cheers /Joe On Tue, 9 Sep 2003, HEINRICH VENTER wrote: > We are using OTP8 at the moment (historic reasons) The code is executing on a Sun U60. The problem is that the code between the first output and the second ouput CAN not change the value of a bound variable!??!! The code below is exactly as it appears, nothing deleted. > We seem to have "fixed" the problem by outputting the following > > finalize_result({TransactionData, R_ResponseCode, TransactionAmount, EndBalance, Flags_2, CostingInfo}, ConfigurationData) -> > io:format("~nTransactionAmount = ~p", [TransactionAmount]), > io:format("~n........ Finalize Result ..........."), > io:format("~n<<< leah:close_connection >>>"), > > io:format("x"), > io:format("~nTransactionAmount voor leah call : ~p", [TransactionAmount]), > io:format("x"), > > (note the two lines that output an x) > But this is a HACK at best. > > -]-[einrich > Teba Bank > > > ##################################################################################### > The information contained in this message and or attachments is intended > only for the person or entity to which it is addressed and may contain > confidential and/or privileged material. Any review, retransmission, > dissemination or other use of, or taking of any action in reliance upon, > this information by persons or entities other than the intended recipient > is prohibited. If you received this in error, please contact the sender and > delete the material from any system and destroy all copies. > ##################################################################################### > From matthias@REDACTED Thu Sep 11 12:30:34 2003 From: matthias@REDACTED (Matthias Lang) Date: Thu, 11 Sep 2003 12:30:34 +0200 Subject: Memory handling description? In-Reply-To: <3F5F46A4.2010106@eth.ericsson.se> References: <3F5F46A4.2010106@eth.ericsson.se> Message-ID: <16224.20170.928817.420233@antilipe.corelatus.se> Zoltan Peter Toth writes: > Can anybody give me a reference to some technical document that > outlines how memory handling (heap, variable storage, message > passing, etc) is done in the Erlang machine ? > (e.g. when is memory allocated, released, etc.) I am not an expert on Erlang's memory handling, but until an expert answers, this may be better than no answer at all. It applies to the "normal" beam system, i.e. not the shared heap. - There is no document about it. Complete source code is freely available but hard to understand. - Erlang uses a garbage collector. If you don't know what that is, the GC FAQ may be of interest: http://www.iecc.com/gclist/GC-faq.html - Each Erlang process has its own heap and its own stack. - There is a separate heap for binaries above a certain size. Such binaries are referred to by reference from e.g. process heaps. - Whenever a process needs more heap space, it will try to recover space by GCing. Failing that, it grows the heap. - Messages are passed between processes by copying them to the target process' heap. Large binaries are passed by reference. - When a process dies, all of its memory is given back to the runtime system. - ETS uses its own pool of memory Matthias From richardc@REDACTED Thu Sep 11 12:41:18 2003 From: richardc@REDACTED (Richard Carlsson) Date: Thu, 11 Sep 2003 12:41:18 +0200 (MET DST) Subject: Memory handling description? In-Reply-To: <16224.20170.928817.420233@antilipe.corelatus.se> References: <3F5F46A4.2010106@eth.ericsson.se> <16224.20170.928817.420233@antilipe.corelatus.se> Message-ID: There are some papers from the HiPE project, under: http://www.csd.uu.se/projects/hipe/publications.shtml that could be of interest; mainly Jesper Wilhelmsson's masters thesis "Exploring Alternative Memory Architectures for Erlang". /Richard On Thu, 11 Sep 2003, Matthias Lang wrote: > Zoltan Peter Toth writes: > > > Can anybody give me a reference to some technical document that > > outlines how memory handling (heap, variable storage, message > > passing, etc) is done in the Erlang machine ? > > (e.g. when is memory allocated, released, etc.) > > I am not an expert on Erlang's memory handling, but until an expert > answers, this may be better than no answer at all. It applies to the > "normal" beam system, i.e. not the shared heap. > > - There is no document about it. Complete source code is freely > available but hard to understand. > > - Erlang uses a garbage collector. If you don't know what that is, > the GC FAQ may be of interest: > > http://www.iecc.com/gclist/GC-faq.html > > - Each Erlang process has its own heap and its own stack. > > - There is a separate heap for binaries above a certain size. > Such binaries are referred to by reference from e.g. process > heaps. > > - Whenever a process needs more heap space, it will try to > recover space by GCing. Failing that, it grows the heap. > > - Messages are passed between processes by copying them to the > target process' heap. Large binaries are passed by reference. > > - When a process dies, all of its memory is given back to the > runtime system. > > - ETS uses its own pool of memory > > Matthias > Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ "Having users is like optimization: the wise course is to delay it." -- Paul Graham From taavi@REDACTED Thu Sep 11 14:23:42 2003 From: taavi@REDACTED (Taavi Talvik) Date: Thu, 11 Sep 2003 15:23:42 +0300 (EEST) Subject: Wither Self (shortish) In-Reply-To: <20030910214426.78e9ff66.cpressey@catseye.mine.nu> Message-ID: <20030911151834.T11938-100000@valu.uninet.ee> On Wed, 10 Sep 2003, Chris Pressey wrote: > The first issue is that I am very strongly against short (cryptic!) > names. (I suppose that might make me a minority in Erlang circles, but > after working on certain legacy source code with variables with names > like O1I1K in it, no amount of peer pressure could make me reconsider my > stance :) So instead of > > h(X, Y, A, B, C) > > I would have something more like > > button_pressed(Button, Window, CList, ProgressBar, FileOptions) > > That's bad enough; but the second issue is that, every time I have to > pass another parameter or a different parameter to the callback, I would > have to change the parameter list in *two* places in the source, > compared to zero with just the fun. What about: button_pressed(button_ID, [ListOfEventOptions], [ListOfUserParameters]) where ListOfEventOptions = [{parent_window, WinId}, {key,value},...] ListOfUserParameters = [{key,value},...] this does not work for legacy code, but for general framework it is clear win. best regards, taavi From ingela@REDACTED Thu Sep 11 15:28:16 2003 From: ingela@REDACTED (Ingela Anderton) Date: Thu, 11 Sep 2003 15:28:16 +0200 Subject: ODBC connection fails References: Message-ID: <16224.30832.258844.423969@gargle.gargle.HOWL> Vlad Dumitrescu wrote: > I've found the problem... After trying even with an Oracle database, I > discovered that scrollable cursors are not supported by the drivers in either > case. > > Should there be a crash when this happens? An error message would be more > appropriate here, I think, if not for other reason than to conform to the > documentation :-) But you did get an error message! E.i. {error,connection_closed} as the connection was terminated in an abnormal way. >(vlad@REDACTED)4> A=odbc:connect("DSN=vlad_test;UID=sysdba;PWD=masterkey",[{trace_driver,on}]). >{error,connection_closed} The process calling odbc:connect/2 did not crash! You also got a SALS error report for the process started by odbc:connect/2 (the connection process) as it was shut down due to abnormal termination of the port program. However due to a subtle spelling misstake the suhtdown crashed with a badarg instated of giving the shutdown reason to be {#Port<0.61>,{port_exit,1}}. However I do agree that there could be a benefit in providing more specific exit codes from the c-port program to make it easier to understand why it terminated abnormally. Humm ... do you mean that when you do: odbc:connect("DSN=vlad_test;UID=sysdba;PWD=masterkey",[{scrollable_cursors, off}]). You get a connection ? But when you do: odbc:connect("DSN=vlad_test;UID=sysdba;PWD=masterkey",[]). you get {error,connection_closed} ? Because I do not quite understand where in the c-port program the crash might have occurred. The oracle driver the we use at OTP does not support scrollable cursors either but we do not need to explicitly disable them. Scrollable cursors are used by the port program by default if they are supported by the driver. If we try using any function that uses the scrollable cursor when it is not supported by the driver we will get an error message. -- /Ingela Ericsson AB - OTP team From michael@REDACTED Thu Sep 11 16:11:00 2003 From: michael@REDACTED (Michael Hobbs) Date: Thu, 11 Sep 2003 09:11:00 -0500 (CDT) Subject: C-- (was Re: BEAM documentation) In-Reply-To: <3F5F942B.23382.140008@localhost> References: <3F5B6E51.16454.289DB0@localhost> <3F5F942B.23382.140008@localhost> Message-ID: <1584.66.41.245.83.1063289460.squirrel@mail.hobbshouse.org> James Hague said: > Luke Gorrie wrote: >> >> Have you considered using existing mid-level languages instead? If so, >> are there any that seem particularly qualified/disqualified? > > An interesting option is C-- (see cminusminus.org). I've always thought that Microsoft should have used something like C-- for .Net, instead of bytecode. Considering that .Net bytecode is compiled to machine code as it is executed, there's not much difference between the {.Net language} -> {.Net bytecode} -> {machine code} system of .Net and the {language} -> {C code} -> {machine code} system of compile-to-C languages like Scheme or Eiffel. Plus, machine-generated C-- code would be just as obfuscated as disassembled machine code or bytecode, so there are really no issues with revealing too much about the original source code. Just an aside, - Michael Hobbs From vlad_dumitrescu@REDACTED Thu Sep 11 17:09:22 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Thu, 11 Sep 2003 17:09:22 +0200 Subject: ODBC connection fails References: <16224.30832.258844.423969@gargle.gargle.HOWL> Message-ID: Hi, > But you did get an error message! E.i. {error,connection_closed} as > the connection was terminated in an abnormal way. Yes, only after sending I realized there was an additional crash due to trying to match the reply with {ok, Ref}. > Humm ... do you mean that when you do: > > odbc:connect("DSN=vlad_test;UID=sysdba;PWD=masterkey",[{scrollable_cursors, > off}]). > > You get a connection ? > > But when you do: > > odbc:connect("DSN=vlad_test;UID=sysdba;PWD=masterkey",[]). > > you get {error,connection_closed} ? Exactly. Ant this is valid for both Firebird 1.4 and Oracle 9.02. regards, Vlad From luke@REDACTED Thu Sep 11 17:46:56 2003 From: luke@REDACTED (Luke Gorrie) Date: 11 Sep 2003 17:46:56 +0200 Subject: Wither Self In-Reply-To: <3F6036AA.5080509@manderp.freeserve.co.uk> References: <3F602D81.7070300@ericsson.com> <3F6036AA.5080509@manderp.freeserve.co.uk> Message-ID: Peter-Henry Mander writes: > The next debate may be over good comment writing practice... anyone > got a comment stripper for Erlang? (-: Sure, (defun strip-erlang-comments () "Remove all comments from an erlang-mode buffer." (interactive) (save-excursion (goto-char (point-min)) (while (re-search-forward "\\s *\\s<.*\\s>" nil t) (delete-region (match-beginning 0) (match-end 0))))) :-) From luke@REDACTED Thu Sep 11 18:10:36 2003 From: luke@REDACTED (Luke Gorrie) Date: 11 Sep 2003 18:10:36 +0200 Subject: Wither Self In-Reply-To: References: <3F602D81.7070300@ericsson.com> <3F6036AA.5080509@manderp.freeserve.co.uk> Message-ID: Luke Gorrie writes: > Peter-Henry Mander writes: > > > The next debate may be over good comment writing practice... anyone > > got a comment stripper for Erlang? (-: > > Sure, > > (defun strip-erlang-comments () Actually, that's so bad that we should pretend I never wrote it :-) Richard Carlsson is your man for automatic source reformatting. Check out the syntax_tools package. Cheers, Luke From cpressey@REDACTED Thu Sep 11 19:50:47 2003 From: cpressey@REDACTED (Chris Pressey) Date: Thu, 11 Sep 2003 10:50:47 -0700 Subject: Wither Self (shortish) In-Reply-To: <20030911151834.T11938-100000@valu.uninet.ee> References: <20030910214426.78e9ff66.cpressey@catseye.mine.nu> <20030911151834.T11938-100000@valu.uninet.ee> Message-ID: <20030911105047.38686a93.cpressey@catseye.mine.nu> On Thu, 11 Sep 2003 15:23:42 +0300 (EEST) Taavi Talvik wrote: > What about: > > button_pressed(button_ID, [ListOfEventOptions], > [ListOfUserParameters]) > > where > ListOfEventOptions = [{parent_window, WinId}, {key,value},...] > ListOfUserParameters = [{key,value},...] > > this does not work for legacy code, but for general framework it is > clear win. Yes, that's especially good for interfaces - but again, it really doesn't help this situation, because I'd have to encode the options list and decode it again (with lists:keysearch/3, or proplists I suppose,) and it's still two places in the source I have to change if something changes, as opposed to zero. And this way, the places are even larger. Basically, defining my callbacks as funs within a main function is the syntactically lightest choice for this task. The only real drawbacks are indentation, as Luke mentioned - and I use a conservative indenting policy, so that's essentially not a problem for me - and the size of the main function, which is easily mitigated by a folding editor like SciTE. -Chris From cpressey@REDACTED Thu Sep 11 20:06:29 2003 From: cpressey@REDACTED (Chris Pressey) Date: Thu, 11 Sep 2003 11:06:29 -0700 Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: <3F5F942B.23382.140008@localhost> References: <3F5B6E51.16454.289DB0@localhost> <3F5F942B.23382.140008@localhost> Message-ID: <20030911110629.0620955c.cpressey@catseye.mine.nu> On Wed, 10 Sep 2003 21:14:19 -0500 "James Hague" wrote: > Luke Gorrie wrote: > > > > Have you considered using existing mid-level languages instead? If > > so, are there any that seem particularly qualified/disqualified? > > I'm partial to both Forth and Lisp, but newer, optimizing Forth > systems tend to be a bit eclectic, and I haven't found a good, > machine code generating Lisp system that's cross-platform. The > Windows port of CMUCL is apparently stalled. I suspect the easiest > option, or the one I'd have the most fun writing, would be a homebrew > Forth. > > An interesting option is C-- (see cminusminus.org). While we're on the general subject (of having the most fun writing [virtual] machine translators) I have to say that I found OpenZz to be an inordinate amount of fun (but that's probably just me.) http://openzz.sourceforge.net/ It's a fairly minimal dynamic parser. So not only is it extremely easy to rapidly prototype a compiler or interpreter with it, it also allows you to experiment with self-modifying grammars... :) -Chris From Erik.Stenman@REDACTED Thu Sep 11 12:47:39 2003 From: Erik.Stenman@REDACTED (Erik Stenman) Date: Thu, 11 Sep 2003 12:47:39 +0200 Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: <3F5F942B.23382.140008@localhost> Message-ID: <006e01c37852$1f29a460$9224fea9@lamppc36> > I'm partial to both Forth and Lisp, but newer, optimizing Forth > systems tend to be a bit eclectic, and I haven't found a good, > machine code generating Lisp system that's cross-platform. The > Windows port of CMUCL is apparently stalled. I suspect the easiest > option, or the one I'd have the most fun writing, would be a homebrew > Forth. > > An interesting option is C-- (see cminusminus.org). If only there would be a C-- compiler at some point. There is still after at least five years not a finished C-- compiler. And the real reason to use C-- would be the promised support for GC, exceptions, and processes, but this is nowhere in sight. When there is a C-- compiler that delivers what was described in the C-- white papers (from 1997 and 2000) And from the Quick C-- page: Our goals for fast compilation are not being met; it appears that the compiler is spending a lot of time in register allocation. Until we get better at profiling, Slow C-- is better name for this compiler. (Off topic: I would suggest the use of Linear Scan to the C-- people to speed up register allocation (in HiPE you can use Linear Scan exactly for this reason.)) A better way might be to use vmgen by Ertl et al (slightly Forth centric but not directly tied to Forth): http://www.complang.tuwien.ac.at/projects/interpreters.html But some bad news for any Erlang implementer: The Core Language is quite easy, but Erlang is really all the magic bifs. To reimplement these bif will take a long time and be very error prone. Trying to reuse the bifs from the OTP C-source would tie you to using the same tag-scheme, GC, and process model as the ERTS by OTP. Erlang has evolved from a nice little language to a huge OTP system, leaving potential new Erlang implementations 10 years behind. I would love to be seen proven wrong by having lots of independent Erlang implementations popping up so please go ahead and make your own implementation. /Erik -- Who has spent the last 7 years trying to keep up with OTP. ------------------------------------------------------------------- I'm Happi, you should be happy. Praeterea censeo "0xCA" scribere Erlang posse. From Erik.Stenman@REDACTED Thu Sep 11 11:50:53 2003 From: Erik.Stenman@REDACTED (Erik Stenman) Date: Thu, 11 Sep 2003 11:50:53 +0200 Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: Message-ID: <005701c3784a$314340f0$9224fea9@lamppc36> Luke Gorrie wrote: > "Erik Stenman" writes: > > > I would suggest using the Icode language in the HiPE > > compiler, It is a very simple language with really only > > 15 different instructions. And > > there is already a compiler from Erlang or BEAM to Icode. (An > > Erlang->Core Erlang->Icode compiler is on its way.) > > Do you implement e.g. the bit syntax in Icode, or is that > done in the runtime system? And will those 15 ops be enough > or do you fear Icode feature-creep? Yes and no. Icode is really just a control flow language. All interesting operations are performed by the call instruction. In this sense the bit syntax is not implemented in Icode. The call instruction can call 'primops' these are implemented by the runtime system (or compiler backend). The bit syntax is handled by calling primops specifically designed for this purpose. In this way Icode is extensible, just add a new primop. The primop can be implemented by the virtual machine as an extra instruction or as a C or Erlang function that can be called. Therefore the 15 ops should be enough and I do not fear feature-creep. Icode has been enough for the HiPE compiler which handles all of Erlang including bit syntax and inlined fp operations. Advantages of using Icode: A working (bug free ;) compiler Erlang to Icode already exists. A compiler Icode to x86 and SPARC exists. (With some changes one can actually produce .S files that can be assembled and linked into a runtime system. (linking of atoms in the code has to be solved...) In this case the runtime system has to be compatible with (read identical to) the current OTP system.) Few instructions -- easy to implement a prototype VM. Disadvantages of using Icode: You have to understand some quirks in the language. There are quite a few primops that have to be implemented somehow. Icode only handles Erlang values (no real support for untagged values) this might be an advantage if you want to write a VM in Erlang for educational purposes. > One thing I find attractive about James's idea of using a > "mid-level" language as the target is that it makes it easy > to write things like the bit syntax: you take the bit-pattern > and generate straight forward code e.g. in terms of logand, > bitshift, etc. Then you let the mid-level-language compiler > worry about making _that_ fast. Well, you can't really do that kind of low level stuff in Icode. In that case I suggest using the HiPE RTL ;) This is a Register Transfer Language suitable which the HiPE compiler uses for implementing some primops and doing tagging and untagging of Erlang values. RTL is a little bit bigger than Icode (27 instructions) but much more low-level. RTL instructions: move multimove alu load store load_address branch switch alub call enter return gctest load_atom load_word_index goto_index label restore_catch comment goto fail_to fload fstore fmov fp fp_unop fconv /Erik -- always ready to provide you with more information about HiPE than you wanted. -------------------------------------- I'm Happi, you should be happy. Praeterea censeo "0xCA" scribere Erlang posse. From erlang@REDACTED Fri Sep 12 08:38:30 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Fri, 12 Sep 2003 07:38:30 +0100 Subject: Wither Self In-Reply-To: References: <3F602D81.7070300@ericsson.com> <3F6036AA.5080509@manderp.freeserve.co.uk> Message-ID: <3F6169E6.403@manderp.freeserve.co.uk> And it doesn't even meet the specification "*without* emacs"!!! Yeah, ok, Lisp =/= Emacs but... Thanks anyway Luke, it made me laugh! (Code makes me laugh? I must be a geek!) Pete. Luke Gorrie wrote: > Luke Gorrie writes: > > >>Peter-Henry Mander writes: >> >> >>>The next debate may be over good comment writing practice... anyone >>>got a comment stripper for Erlang? (-: >> >>Sure, >> >> (defun strip-erlang-comments () > > > Actually, that's so bad that we should pretend I never wrote it :-) > > Richard Carlsson is your man for automatic source > reformatting. Check out the syntax_tools package. > > Cheers, > Luke > > > From ingela@REDACTED Fri Sep 12 10:47:21 2003 From: ingela@REDACTED (Ingela Anderton) Date: Fri, 12 Sep 2003 10:47:21 +0200 Subject: ODBC connection fails References: <16224.30832.258844.423969@gargle.gargle.HOWL> Message-ID: <16225.34841.799469.184632@gargle.gargle.HOWL> Vlad Dumitrescu wrote: > odbc:connect("DSN=vlad_test;UID=sysdba;PWD=masterkey",[{scrollable_cursors, > > off}]). > > > > You get a connection ? > > > > But when you do: > > > > odbc:connect("DSN=vlad_test;UID=sysdba;PWD=masterkey",[]). > > > > you get {error,connection_closed} ? > > Exactly. Ant this is valid for both Firebird 1.4 and Oracle 9.02. My guess is that both these drivers only support odbc 2.0 standard. The erlang odbc application uses the odbc 3.0 standard but the only thing that it uses that does not seem to be backwards compatible with 2.0 seems to be the test for what level of scrollable cursors that driver supports. The erlang odbc application will by default try to use scrollable cursor, but it has to check that they are supported by the driver. When the user disables them explicitly there is no need to perform the test. >From the odbc users guide: The Erlang ODBC application is designed using the version 3.0 of the ODBC-standard, however using the option {scrollable_cursors, off} for a connection has been known to make it work for at least some 2.X drivers. -- /Ingela Ericsson AB - OTP team From erlang@REDACTED Fri Sep 12 12:06:13 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Fri, 12 Sep 2003 11:06:13 +0100 Subject: Erlang X11 Message-ID: <3F619A95.2050905@manderp.freeserve.co.uk> Hi Tony, hi Christian, I've cvs'ed and tried the x11 demo, and I like it, even if it is a bit green. I wonder what your plans are for x11. Do you want to simply make a 1:1 binding to the X11R6 API, or do you want to explore making an Erlang GUI "thing" (module, behaviour,.. what?)? There has been a thread on erlang.org about a "functional" widget library, and I'm not too impressed with gs, I'm stressing its ability. Can you share your thoughts & plans with me? There's been discussions on how to implement a GUI applying the Erlang philosophy [1], but not much code has been generated. How can I help jumpstart the process? Pete. [1] FW: UI thoughts, Vlad Dumitrescu http://www.erlang.org/ml-archive/erlang-questions/200303/msg00107.html From bjarne@REDACTED Fri Sep 12 14:22:15 2003 From: bjarne@REDACTED (=?iso-8859-1?Q?Bjarne_D=E4cker?=) Date: Fri, 12 Sep 2003 14:22:15 +0200 Subject: Erlang/OTP User Conference 2003 Message-ID: <004501c37928$80b98340$d40d69d4@segeltorp> Hello All Erlang users, developers, friends, hangers-on etc. are invited to this year's Erlang/OTP User Conference. It is the ninth since the beginning and it will take place in the same lecture hall as the last years. Papers, demos etc. are invited. Please see the call-for-papers at http://www.erlang.se/euc/03/ Welcome Bjarne -------------- next part -------------- An HTML attachment was scrubbed... URL: From vlad_dumitrescu@REDACTED Fri Sep 12 14:46:54 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Fri, 12 Sep 2003 14:46:54 +0200 Subject: ODBC connection fails References: <16224.30832.258844.423969@gargle.gargle.HOWL> <16225.34841.799469.184632@gargle.gargle.HOWL> Message-ID: > My guess is that both these drivers only support odbc 2.0 standard. Yes, this seems to be the case. So now I know why :-) Should odbc:first and friends work even without scrollable cursors? From the documentation, it would seem thet they should work (forward only), but I only get an "{error, scrollable_cursors_disabled}". Is this right? Thanks for the help! Vlad From luke@REDACTED Fri Sep 12 15:35:09 2003 From: luke@REDACTED (Luke Gorrie) Date: 12 Sep 2003 15:35:09 +0200 Subject: Wither Self In-Reply-To: <3F6169E6.403@manderp.freeserve.co.uk> References: <3F602D81.7070300@ericsson.com> <3F6036AA.5080509@manderp.freeserve.co.uk> <3F6169E6.403@manderp.freeserve.co.uk> Message-ID: Peter-Henry Mander writes: > And it doesn't even meet the specification "*without* emacs"!!! The really bad bit was that it didn't recognise that e.g. % inside a string is not a comment. I was about to rewrite it to "delete everything that syntax-colouring decided was a comment", but thought better of it. :-) Aside: one very nice Emacs hack I recently got is "htmlize.el", which takes a buffer and generates HTML with the same syntax colouring. Handy when you want to publish code snippets on the web. http://fly.srk.fer.hr/~hniksic/emacs/htmlize.el -Luke From ingela@REDACTED Fri Sep 12 16:49:45 2003 From: ingela@REDACTED (Ingela Anderton) Date: Fri, 12 Sep 2003 16:49:45 +0200 Subject: ODBC connection fails References: <16224.30832.258844.423969@gargle.gargle.HOWL> <16225.34841.799469.184632@gargle.gargle.HOWL> Message-ID: <16225.56585.998213.279895@gargle.gargle.HOWL> Vlad Dumitrescu wrote: > Should odbc:first and friends work even without scrollable cursors? From the > documentation, it would seem thet they should work (forward only), but I only > get an "{error, scrollable_cursors_disabled}". Is this right? Yes it is right! The functions first/[1,2], last/[1,2], prev[1,2] and select/[3,4] where the position argument is one of {relative, Pos} | {absolute, Pos} are all implemented using scrollable cursors. Also stated in the documentation: "Alas some drivers only support sequential traversal of the result set, e.i. they do not support what in the ODBC world is known as scrollable cursors. This will have the effect that functions such as first/[1,2], last/[1,2], prev[1,2], etc may return {error, driver_does_not_support_function}" Description of select_count from the man page: Executes a SQL SELECT query and associates the result set with the connection. A cursor is positioned before the first row in the result set and the tuple {ok, NrRows} is returned. E.i. calling next will give you the first row of the result set and then you can keep traversing the resut set sequentially by calling next until you reach the end of the result set. You can also use select/[3,4] with postion next if you want to get for instance the 10 next rows. Also if you look at the man page for the function first and see what are the possible error reasons you will see: Reason = result_set_does_not_exist | driver_does_not_support_function | scrollable_cursors_disabled | process_not_owner_of_odbc_connection | CommonReason See common data types. So you can't say it was not documented ;) -- /Ingela Ericsson AB - OTP team From Marc.Vanwoerkom@REDACTED Fri Sep 12 17:17:45 2003 From: Marc.Vanwoerkom@REDACTED (Marc Ernst Eddy van Woerkom) Date: Fri, 12 Sep 2003 17:17:45 +0200 (MEST) Subject: Wither Self In-Reply-To: (message from Luke Gorrie on 12 Sep 2003 15:35:09 +0200) Message-ID: <200309121517.h8CFHjM19395@bonsai.fernuni-hagen.de> > Aside: one very nice Emacs hack I recently got is "htmlize.el", which > takes a buffer and generates HTML with the same syntax > colouring. Handy when you want to publish code snippets on the web. > > http://fly.srk.fer.hr/~hniksic/emacs/htmlize.el Thanks a lot for that hint. Works fine. I use dired to browse a directory and use m to mark the files I want to htmlize. Then call up htmlize-many-files-dired and all marked ones get their html counterparts. Very useful. Is it possible to switch from the dark color scheme to a light color scheme - or do I get what I configured my Emacs to? Regards, Marc From vlad_dumitrescu@REDACTED Fri Sep 12 18:01:21 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Fri, 12 Sep 2003 18:01:21 +0200 Subject: ODBC connection fails References: <16224.30832.258844.423969@gargle.gargle.HOWL><16225.34841.799469.184632@gargle.gargle.HOWL> <16225.56585.998213.279895@gargle.gargle.HOWL> Message-ID: Hi again, What misguided me was the following statement (my emphasis) > "Alas some drivers only support sequential traversal of the result > set, e.i. they do not support what in the ODBC world is known as > scrollable cursors. This will have the effect that functions such as > first/[1,2], last/[1,2], prev[1,2], etc ***may*** return {error, > driver_does_not_support_function}" Maybe it's only my bad English, but "may" implies that it also "may not". > So you can't say it was not documented ;) No, I didn't say that, only that the way I interpreted the docs hinted that it "might" work. Thanks again, and now I know that I can use odbc:next without first calling odbc:first (which wasn't obvious to me, but reading the documentation very carefully, one can deduce it) /Vlad From luke@REDACTED Fri Sep 12 18:09:30 2003 From: luke@REDACTED (Luke Gorrie) Date: 12 Sep 2003 18:09:30 +0200 Subject: Wither Self In-Reply-To: <200309121517.h8CFHjM19395@bonsai.fernuni-hagen.de> References: <200309121517.h8CFHjM19395@bonsai.fernuni-hagen.de> Message-ID: Marc Ernst Eddy van Woerkom writes: > Is it possible to switch from the dark color scheme to a light color > scheme - or do I get what I configured my Emacs to? You get what Emacs is configured to. So if you want more colour schemes, you might want to combine this with color-theme.el: http://www.emacswiki.org/elisp/color-theme.el.gz That includes a whole bunch of complete Emacs colour schemes to choose from. BTW, even better than htmlize is Emacs's builtin command `ps-print-buffer-with-faces', which is the same thing but with postscript output for printing. (Use a C-u prefix argument to save the output to a file instead of sending it directly to the printer.) To get nice looking printed results on our colour printer I had to tweak my printing variables a little bit. Here's what Works For Me: (require 'ps-print) (setq ps-paper-type 'a4) (setq ps-landscape-mode t) (setq ps-number-of-columns 2) (ps-extend-face '(default "black" nil nil) 'merge) (ps-extend-face '(font-lock-comment-face nil nil bold) 'merge) (ps-extend-face '(font-lock-function-name-face "darkblue" nil bold) nil) (ps-extend-face '(font-lock-string-face "darkblue" nil nil) nil) (ps-extend-face '(font-lock-builtin-face "black" nil nil) nil) (ps-extend-face '(font-lock-variable-name-face "orchid" nil bold) nil) (ps-extend-face '(font-lock-warning-face "red" nil nil) nil) (ps-extend-face '(font-lock-keyword-face "darkcyan" nil nil) nil) (ps-extend-face '(font-lock-type-face "darkgreen" nil nil) nil) Example output (stdlib's string.erl) here: http://www.bluetail.com/~luke/misc/string_erl.ps I've noticed that Erlang programs are typically quite nice to read in printed form. C programs are not. Cheers, Luke From Marc.Vanwoerkom@REDACTED Fri Sep 12 18:21:17 2003 From: Marc.Vanwoerkom@REDACTED (Marc Ernst Eddy van Woerkom) Date: Fri, 12 Sep 2003 18:21:17 +0200 (MEST) Subject: Wither Self In-Reply-To: (message from Luke Gorrie on 12 Sep 2003 18:09:30 +0200) Message-ID: <200309121621.h8CGLHA24353@bonsai.fernuni-hagen.de> > To get nice looking printed results on our colour printer I had to > tweak my printing variables a little bit. Here's what Works For Me: So we have html renderings of syntax colored listings and direct printouts .. but what about putting syntax colored listings into TeX? Background: I just had to write a documentation of a Pascal program, which I did with LaTeX2e (to render into PDF with pdfLaTeX), it contained about 10-20 pages of blabla and about 100 pages with the 5000 lines of Pascal as appendix. http://www.stud.fernuni-hagen.de/q5480035/propra01580 Getting that to work forced me to use such a script ------------------------------------------------------------ #!/usr/local/bin/bash # prepare pascal sources SRC=../src for f in \ calc.pas \ numbers.pas \ numarith.pas \ numutil.pas \ propra.pas \ util.pas \ zeros.pas do echo "creating file '$f.tex'" echo "% created by makedoku.sh on `date`" >$f.tex echo "\begin{verbatim}" >>$f.tex # remove DOS ^M and ^Z, Umlaut to TeX, tab to 8 spaces # complicated Umlaut translation due to sed etc # not able to deal with non Ascii chars.. cat $SRC/$f | tr -d "\032\r" | tr "\304" "~" | sed -e "s/~/Ae/g" | tr "\326" "~" | sed -e "s/~/Oe/g" | tr "\334" "~" | sed -e "s/~/Ue/g" | tr "\344" "~" | sed -e "s/~/ae/g" | tr "\366" "~" | sed -e "s/~/oe/g" | tr "\374" "~" | sed -e "s/~/ue/g" | tr "\t" "~ " | sed -e "s/~/ /g" \ >>$f.tex echo "\end{verbatim}" >>$f.tex done # tex 2 times echo "first pdflatex pass.." pdflatex doku-mvw.tex echo "second pdflatex pass.." pdflatex doku-mvw.tex ------------------------------------------------------------ It produced cleansed versions (no Umlauts, tabs, ..) braced by a verbatim environment. In the main .tex doc I included them. But pdflatex is able to support colors. I would have loved to put in syntax coloured versions of the listings. Any idea? Regards, Marc From Marc.Vanwoerkom@REDACTED Fri Sep 12 19:13:04 2003 From: Marc.Vanwoerkom@REDACTED (Marc Ernst Eddy van Woerkom) Date: Fri, 12 Sep 2003 19:13:04 +0200 (MEST) Subject: Wither Self In-Reply-To: (message from Luke Gorrie on 12 Sep 2003 18:09:30 +0200) Message-ID: <200309121713.h8CHD4T28350@bonsai.fernuni-hagen.de> Hmm I just notice that htmlize doesn't work as flawless as I hoped. If I just run it on a file, it produces an .html without syntax colorng, I need to visit the .erl in a buffer first, and scroll through it (perhaps to add the color decorations..) then it works. Hmm. Regards, Marc From luther@REDACTED Fri Sep 12 21:49:16 2003 From: luther@REDACTED (Luther Huffman) Date: Fri, 12 Sep 2003 15:49:16 -0400 (EDT) Subject: Install fails during "make install" Message-ID: <7812.69.3.204.76.1063396156.spork@webmail.widgeon.org> I'm using Mac OS X 10.2.6 and trying to build R9C-0 from source. The build process goes without a hitch, as does most of "make install". I'm seeing, however, something curious when the make script invokes Install: ... cd /usr/local/lib/erlang && ./Install -minimal /usr/local/lib/erlang ./Install: [: too many arguments Formatting manual pages (this may take a while...) make: *** [install.Install] Error 127 Any ideas? Regards, Luther Huffman From kent@REDACTED Sat Sep 13 18:02:28 2003 From: kent@REDACTED (Kent Boortz) Date: 13 Sep 2003 18:02:28 +0200 Subject: Install fails during "make install" In-Reply-To: <7812.69.3.204.76.1063396156.spork@webmail.widgeon.org> References: <7812.69.3.204.76.1063396156.spork@webmail.widgeon.org> Message-ID: "Luther Huffman" writes: > I'm using Mac OS X 10.2.6 and trying to build R9C-0 from source. The build > process goes without a hitch, as does most of "make install". I'm seeing, > however, something curious when the make script invokes Install: > > ... > cd /usr/local/lib/erlang && ./Install -minimal /usr/local/lib/erlang > ./Install: [: too many arguments > Formatting manual pages (this may take a while...) > make: *** [install.Install] Error 127 Please add a new line with the command "set -x" after the initial comments in "/usr/local/lib/erlang/Install" and run % cd /usr/local/lib/erlang && ./Install -minimal /usr/local/lib/erlang again. This will give us a trace from the execution of the Install script. You may also include a printout of the environment used % set % setenv kent From luther@REDACTED Sat Sep 13 18:56:20 2003 From: luther@REDACTED (Luther Huffman) Date: Sat, 13 Sep 2003 12:56:20 -0400 Subject: Install fails during "make install" In-Reply-To: Message-ID: <32BD264C-E60B-11D7-A21D-00039366D058@widgeon.org> Thanks to those who responded. Since others had successfully built the release, I thought perhaps something had been damaged in my environment by my experimenting with new developer tools, including Apple's June 2003 release of gcc-3.3 which has just this month been replaced. That particular developer release had caused me serious trouble with wxWindows and Python and I had previously backed it out (long before installing erlang). On the off chance that I had missed something I created a new account, removed all tools, did a clean install of the developer tools (December 2002, gcc-3.1), then tried to build and install Erlang. It worked. I don't know whether it was the tools, an environment variable or an ill wind on the subetheric but it's over now. :-) Thanks for the assistance, Luther From sean.hinde@REDACTED Sat Sep 13 19:35:17 2003 From: sean.hinde@REDACTED (Sean Hinde) Date: Sat, 13 Sep 2003 18:35:17 +0100 Subject: OS X patch for run_erl.c Message-ID: Hi, The following patch to run_erl.c is required for Erlang to run in embedded mode under OS X. Without this patch run_erl fails to create the pipe in /tmp Hopefully this will make it into R9C-1, but in the meantime here it is in case anyone else has encountered the problem and needs a fix now. Regs, Sean [HugeMac:~/Desktop] sean% diff -u otp_src_R9C-0.orig/erts/etc/unix/run_erl.c otp_src_R9C-0/erts/etc/unix/run_erl.c --- otp_src_R9C-0.orig/erts/etc/unix/run_erl.c Mon Jul 7 13:01:10 2003 +++ otp_src_R9C-0/erts/etc/unix/run_erl.c Sat Sep 13 18:26:53 2003 @@ -738,7 +738,11 @@ */ static int create_fifo(char *name, int perm) { - if ((mknod(name, S_IFIFO | perm, 0) < 0) && (errno != EEXIST)) +#ifdef HAVE_MACH_O_DYLD_H + if ((mkfifo(name, perm) < 0) && (errno != EEXIST)) +#else + if ((mknod(name, S_IFIFO | perm, 0) < 0) && (errno != EEXIST)) +#endif return -1; return 0; } From taj.khattra@REDACTED Mon Sep 15 00:11:09 2003 From: taj.khattra@REDACTED (Taj Khattra) Date: 14 Sep 2003 22:11:09 -0000 Subject: eddie technical reports Message-ID: <20030914221109.1376.qmail@infidel.telus.net> the eddie technical reports links at http://eddie.sourceforge.net/techrep.html are dead - is anybody aware of some other place where i could find them ? (already googled for them, but no luck) thanks -taj From luke@REDACTED Mon Sep 15 04:48:31 2003 From: luke@REDACTED (Luke Gorrie) Date: 15 Sep 2003 04:48:31 +0200 Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: <006e01c37852$1f29a460$9224fea9@lamppc36> References: <006e01c37852$1f29a460$9224fea9@lamppc36> Message-ID: "Erik Stenman" writes: > But some bad news for any Erlang implementer: > The Core Language is quite easy, but Erlang is really all the magic > bifs. To reimplement these bif will take a long time and be very > error prone. Trying to reuse the bifs from the OTP C-source would > tie you to using the same tag-scheme, GC, and process model as > the ERTS by OTP. Which BIFs are hard? The process stuff all seems straight forward enough. The ETS primitives should be okay if your target has hash tables and trees. I don't see much tricky stuff from browsing the C code. What'm I missing? > Erlang has evolved from a nice little language to a huge OTP system, > leaving potential new Erlang implementations 10 years behind. On the other hand it's very practical that we're all using the same Erlang system. How boring it would be if there were ten Erlangs, and Mnesia only worked on one, Yaws on a couple of others, etc. BTW, kudos are due to you HiPE guys both for building your stuff on the standard Erlang from OTP and for writing all the code in Erlang. No doubt you were sorely tempted to start from scratch, but actually getting it integrated into OTP is a great accomplishment. P.S., it's nice to have these threads about BEAM. I just had a browse of the C code, which I haven't really done before. I've observed that one can have large C programs on the computer (Emacs, Linux, etc) without ever knowing how they work, but after you first actually open the code you're inevitably familiar with it within a year or so :-) Cheers, Luke From Zoltan.Toth@REDACTED Mon Sep 15 08:25:14 2003 From: Zoltan.Toth@REDACTED (Zoltan Peter Toth) Date: Mon, 15 Sep 2003 08:25:14 +0200 Subject: Build problem with R9C-0 Message-ID: <3F655B4A.4070506@eth.ericsson.se> Hi, Can anybody advise me what's wrong with my build: (it's Debian Linux, gcc 3.0 [but 2.95 does the same]. I attached my config.cache.) ---------- === Entering application hipe make[3]: Entering directory `.../otp_src_R9C-0/lib/hipe/rtl' erlc -W -bbeam +debug_info -o../ebin hipe_rtl.erl erlc -W -bbeam +debug_info -o../ebin hipe_rtl_cfg.erl erlc -W -bbeam +debug_info -o../ebin hipe_rtl_cse.erl erlc -W -bbeam +debug_info -o../ebin hipe_rtl_ebb.erl erlc -W -bbeam +debug_info -o../ebin hipe_rtl_liveness.erl erlc -W -bbeam +debug_info -o../ebin hipe_rtl_prop.erl erlc -W -bbeam +debug_info -o../ebin hipe_icode2rtl.erl erlc -W -bbeam +debug_info -o../ebin hipe_tagscheme.erl .../otp_src_R9C-0/lib/hipe/rtl/hipe_tagscheme.erl:695: undefined macro ''P_OFF_HEAP_OVERHEAD'' .../otp_src_R9C-0/lib/hipe/rtl/hipe_tagscheme.erl:37: function finalize_bin/4 undefined --------- (The latter error is a consequence of the former, as it wants to export the erroneous function.) And really, the string P_OFF_HEAP_OVERHEAD was not found in the whole source tree with a recursive egrep. Of course, hipe does not work. Thanks for any advice. Zoltan -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: config.cache URL: From Bengt.Kleberg@REDACTED Mon Sep 15 10:07:01 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Mon, 15 Sep 2003 10:07:01 +0200 Subject: OS X patch for run_erl.c In-Reply-To: References: Message-ID: <3F657325.3070702@ericsson.com> Sean Hinde wrote: > Hi, > > The following patch to run_erl.c is required for Erlang to run in > embedded mode under OS X. Without this patch run_erl fails to create the ...deleted > +#ifdef HAVE_MACH_O_DYLD_H > + if ((mkfifo(name, perm) < 0) && (errno != EEXIST)) > +#else > + if ((mknod(name, S_IFIFO | perm, 0) < 0) && (errno != EEXIST)) > +#endif perhaps mkfifo() is deprecated (or something even worse :-), but would it not have been better to test like this: #ifdef HAVE_MKFIFO if ((mkfifo(name, perm) < 0) && (errno != EEXIST)) #else if ((mknod(name, S_IFIFO | perm, 0) < 0) && (errno != EEXIST)) #endif bengt, who really thinks #ifdef should only be used in libraries, not in ''real'' code. From erlang@REDACTED Mon Sep 15 10:07:04 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Mon, 15 Sep 2003 09:07:04 +0100 Subject: Erlang -> HTML syntax colouring (was Re: Wither Self) In-Reply-To: <200309121713.h8CHD4T28350@bonsai.fernuni-hagen.de> References: <200309121713.h8CHD4T28350@bonsai.fernuni-hagen.de> Message-ID: <3F657328.4080105@manderp.freeserve.co.uk> Ahem, (blows own trumpet) SciTE will export coloured syntax highlighted Erlang code as html quite well, thanks to the Erlang lexer I've cobbled together. I'm trying to get a response from the main author of SciTE to have it included in the distribution. No answer yet... I can issue a source code patch for Erlang syntax parsing in the mean time for whoever is interested. I need a few more beta testers, so please give it your worst! (-: Pete. Marc Ernst Eddy van Woerkom wrote: > Hmm I just notice that htmlize doesn't work as flawless as I hoped. > If I just run it on a file, it produces an .html without syntax colorng, > I need to visit the .erl in a buffer first, and scroll through it > (perhaps to add the color decorations..) then it works. Hmm. > > Regards, > Marc > > > From Erik.Stenman@REDACTED Mon Sep 15 10:39:47 2003 From: Erik.Stenman@REDACTED (Erik Stenman) Date: Mon, 15 Sep 2003 10:39:47 +0200 Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: Message-ID: <001101c37b64$ec01e8c0$b701010a@lamppc36> > > The Core Language is quite easy, but Erlang is really all the magic > > bifs. To reimplement these bif will take a long time and be very > > error prone. Trying to reuse the bifs from the OTP C-source would > > tie you to using the same tag-scheme, GC, and process model as > > the ERTS by OTP. > > Which BIFs are hard? I did not mean that any of the BIFs would be particularly hard, it is the sheer number of BIFs that makes it hard. (See below for a list of BIFs in R9) Most of these BIFs are dependent on the tag scheme, the layout and content of the PCB, and of course the calling conventions for BIFs. Many of the BIFs also have subtle assumptions on how the GC works and on how process scheduling in the BEAM works. This means that you can not take the C code for these BIFs and use it in your new Erlang system if you plan to change any of the above mentioned aspects of the system. Hence you are faced with three options: 1. Reimplement all the BIFs yourself to work with your system. It is a major undertaking to get all of them working (If you take a look at other Erlang implementations (e.g., ETOS and Gerl) you will see that it is in the support of all these BIFs that these systems lack. It just takes to much time to reimplement all this and get it bug free. 2. Try to rewrite the BIFs to work with your system hoping that you don't overlook some important assumption in the code that don't hold in your system. This looks quite error prone to me, and your system can not be to different from BEAM for this to work. 3. Reuse the BEAM system as it is and implement your system on top of it, then when it works you can start trying to slowly change things in the BEAM system that you don't like. This is the approach we took in HiPE, and we are now in a position where we actually can have an influence on the ERTS by OTP. (Like a new tagging scheme, a unified heap model, Core Erlang etc things that slowly creep in to the OTP system ;) > On the other hand it's very practical that we're all using > the same Erlang system. How boring it would be if there were > ten Erlangs, and Mnesia only worked on one, Yaws on a couple > of others, etc. Well this it what I mean. In order for all application to work on all Erlang implementations the set of BIFs and how they work must be identical. This is the hard part. > BTW, kudos are due to you HiPE guys both for building your > stuff on the standard Erlang from OTP and for writing all the > code in Erlang. No doubt you were sorely tempted to start > from scratch, but actually getting it integrated into OTP is > a great accomplishment. Thanks. >From my view this was the only possible way to do it. We wanted to be able to benchmark different implementation techniques on REAL Erlang applications. These types of applications tends to use all the strange BIFs in the system and depend on quirks in the current implementation, so we had to be 100% compatible to OTP. What better way to be compatible than using the same source? > P.S., it's nice to have these threads about BEAM. I just had > a browse of the C code, which I haven't really done before. > I've observed that one can have large C programs on the > computer (Emacs, Linux, etc) without ever knowing how they > work, but after you first actually open the code you're > inevitably familiar with it within a year or so :-) ...mmm... I feel like seven years is not enough for grocking the BEAM and its BIFs ;) /Erik ------------------------------------------------------------------- I'm Happi, you should be happy. Praeterea censeo "0xCA" scribere Erlang posse. For your reference, here are some BIFs you would have to implement to be compatible with R9 (remember that you need to support bignum and floating-point arithmetic also): ubif erlang:abs/1 ubif 'erl.lang.number':abs/1 ebif_abs_1 bif erlang:apply/3 bif 'erl.lang':apply/3 ebif_apply_3 bif erlang:atom_to_list/1 bif 'erl.lang.atom':to_string/1 ebif_atom_to_string_1 atom_to_list_1 bif erlang:binary_to_list/1 bif 'erl.lang.binary':to_list/1 ebif_binary_to_list_1 bif erlang:binary_to_list/3 bif 'erl.lang.binary':to_list/3 ebif_binary_to_list_3 bif erlang:binary_to_term/1 bif 'erl.lang.binary':to_term/1 ebif_binary_to_term_1 bif erlang:check_process_code/2 bif 'erl.system.code':check_process/2 ebif_check_process_code_2 bif erlang:date/0 bif 'erl.util.date':today/0 ebif_date_0 bif erlang:delete_module/1 bif 'erl.system.code':delete/1 ebif_delete_module_1 bif erlang:display/1 bif 'erl.system.debug':display/1 ebif_display_1 bif erlang:display_string/1 bif 'erl.system.debug':display_string/1 ebif_display_string_1 bif erlang:display_nl/0 bif 'erl.system.debug':display_nl/0 ebif_display_nl_0 ubif erlang:element/2 ubif 'erl.lang.tuple':element/2 ebif_element_2 bif erlang:erase/0 bif 'erl.lang.proc.pdict':erase/0 ebif_erase_0 bif erlang:erase/1 bif 'erl.lang.proc.pdict':erase/1 ebif_erase_1 bif erlang:exit/1 bif 'erl.lang':exit/1 ebif_exit_1 bif erlang:exit/2 bif 'erl.lang.proc':signal/2 ebif_signal_2 exit_2 bif erlang:external_size/1 bif 'erl.lang.term':external_size/1 ebif_external_size_1 ubif erlang:float/1 ubif 'erl.lang.number':float/1 ebif_float_1 bif erlang:float_to_list/1 bif 'erl.lang.float':to_string/1 ebif_float_to_string_1 float_to_list_1 bif erlang:fun_info/2 bif 'erl.lang.function':info/2 ebif_fun_info_2 bif erlang:garbage_collect/0 bif 'erl.system':garbage_collect/0 ebif_garbage_collect_0 bif erlang:garbage_collect/1 bif 'erl.system':garbage_collect/1 ebif_garbage_collect_1 bif erlang:get/0 bif 'erl.lang.proc.pdict':get/0 ebif_get_0 bif erlang:get/1 bif 'erl.lang.proc.pdict':get/1 ebif_get_1 bif erlang:get_keys/1 bif 'erl.lang.proc.pdict':get_keys/1 ebif_get_keys_1 bif erlang:group_leader/0 bif 'erl.lang.proc':group_leader/0 ebif_group_leader_0 bif erlang:group_leader/2 bif 'erl.lang.proc':set_group_leader/2 ebif_group_leader_2 bif erlang:halt/0 bif 'erl.lang.node':halt/0 ebif_halt_0 bif erlang:halt/1 bif 'erl.lang.node':halt/1 ebif_halt_1 bif erlang:phash/2 bif erlang:phash2/1 bif erlang:phash2/2 bif 'erl.lang.term':hash/1 ebif_phash2_1 bif 'erl.lang.term':hash/2 ebif_phash2_2 ubif erlang:hd/1 ubif 'erl.lang.list':hd/1 ebif_hd_1 bif erlang:integer_to_list/1 bif 'erl.lang.integer':to_string/1 ebif_integer_to_string_1 integer_to_list_1 bif erlang:is_alive/0 bif 'erl.lang.node':is_alive/0 ebif_is_alive_0 ubif erlang:length/1 ubif 'erl.lang.list':length/1 ebif_length_1 bif erlang:link/1 bif 'erl.lang.proc':link/1 ebif_link_1 bif erlang:list_to_atom/1 bif 'erl.lang.atom':from_string/1 ebif_string_to_atom_1 list_to_atom_1 bif erlang:list_to_binary/1 bif 'erl.lang.binary':from_list/1 ebif_list_to_binary_1 bif erlang:list_to_float/1 bif 'erl.lang.float':from_string/1 ebif_string_to_float_1 list_to_float_1 bif erlang:list_to_integer/1 bif 'erl.lang.integer':from_string/1 ebif_string_to_integer_1 list_to_integer_1 bif erlang:list_to_pid/1 bif 'erl.lang.proc':string_to_pid/1 ebif_string_to_pid_1 list_to_pid_1 bif erlang:list_to_tuple/1 bif 'erl.lang.tuple':from_list/1 ebif_list_to_tuple_1 bif erlang:load_module/2 bif 'erl.system.code':load/2 ebif_load_module_2 bif erlang:loaded/0 bif 'erl.system.code':loaded/0 ebif_loaded_0 bif erlang:localtime/0 bif 'erl.util.date':local/0 ebif_localtime_0 bif erlang:localtime_to_universaltime/2 bif 'erl.util.date':local_to_utc/2 ebif_localtime_to_universaltime_2 bif erlang:make_ref/0 bif 'erl.lang.ref':make/0 ebif_make_ref_0 bif erlang:md5/1 bif 'erl.util.crypt.md5':digest/1 ebif_md5_1 bif erlang:md5_init/0 bif 'erl.util.crypt.md5':init/0 ebif_md5_init_0 bif erlang:md5_update/2 bif 'erl.util.crypt.md5':update/2 ebif_md5_update_2 bif erlang:md5_final/1 bif 'erl.util.crypt.md5':final/1 ebif_md5_final_1 bif erlang:module_loaded/1 bif 'erl.system.code':is_loaded/1 ebif_module_loaded_1 bif erlang:function_exported/3 bif 'erl.system.code':is_loaded_function/3 ebif_is_loaded_function_3 function_exported_3 bif erlang:monitor_node/2 bif 'erl.lang.node':monitor/2 ebif_monitor_node_2 ubif erlang:node/1 ubif 'erl.lang.node':node/1 ebif_node_1 ubif erlang:node/0 ubif 'erl.lang.node':node/0 ebif_node_0 bif erlang:nodes/1 bif 'erl.lang.node':nodes/1 ebif_nodes_1 bif erlang:now/0 bif 'erl.util.time':now/0 ebif_now_0 bif erlang:open_port/2 bif erlang:pid_to_list/1 bif 'erl.lang.proc':pid_to_string/1 ebif_pid_to_string_1 pid_to_list_1 bif erlang:port_info/1 bif 'erl.lang.port':info/1 ebif_port_info_1 bif erlang:port_info/2 bif 'erl.lang.port':info/2 ebif_port_info_2 bif erlang:ports/0 bif 'erl.lang.node':ports/0 ebif_ports_0 bif erlang:pre_loaded/0 bif 'erl.system.code':preloaded/0 ebif_pre_loaded_0 bif erlang:process_flag/2 bif 'erl.lang.proc':set_flag/2 ebif_process_flag_2 bif erlang:process_flag/3 bif 'erl.lang.proc':set_flag/3 ebif_process_flag_3 bif erlang:process_info/1 bif 'erl.lang.proc':info/1 ebif_process_info_1 bif erlang:process_info/2 bif 'erl.lang.proc':info/2 ebif_process_info_2 bif erlang:processes/0 bif 'erl.lang.node':processes/0 ebif_processes_0 bif erlang:purge_module/1 bif 'erl.system.code':purge/1 ebif_purge_module_1 bif erlang:put/2 bif 'erl.lang.proc.pdict':put/2 ebif_put_2 bif erlang:register/2 bif 'erl.lang.node':register/2 ebif_register_2 bif erlang:registered/0 bif 'erl.lang.node':registered/0 ebif_registered_0 ubif erlang:round/1 ubif 'erl.lang.number':round/1 ebif_round_1 ubif erlang:self/0 ubif 'erl.lang.proc':self/0 ebif_self_0 bif erlang:setelement/3 bif 'erl.lang.tuple':setelement/3 ebif_setelement_3 ubif erlang:size/1 ubif 'erl.lang.term':size/1 ebif_size_1 bif erlang:spawn/3 bif 'erl.lang.proc':spawn/3 ebif_spawn_3 bif erlang:spawn_link/3 bif 'erl.lang.proc':spawn_link/3 ebif_spawn_link_3 bif erlang:split_binary/2 bif 'erl.lang.binary':split/2 ebif_split_binary_2 bif erlang:statistics/1 bif 'erl.system':statistics/1 ebif_statistics_1 bif erlang:term_to_binary/1 bif 'erl.lang.binary':from_term/1 ebif_term_to_binary_1 bif erlang:term_to_binary/2 bif 'erl.lang.binary':from_term/2 ebif_term_to_binary_2 bif erlang:throw/1 bif 'erl.lang':throw/1 ebif_throw_1 bif erlang:time/0 bif 'erl.util.date':time_of_day/0 ebif_time_0 ubif erlang:tl/1 ubif 'erl.lang.list':tl/1 ebif_tl_1 ubif erlang:trunc/1 ubif 'erl.lang.number':trunc/1 ebif_trunc_1 bif erlang:tuple_to_list/1 bif 'erl.lang.tuple':to_list/1 ebif_tuple_to_list_1 bif erlang:universaltime/0 bif 'erl.util.date':utc/0 ebif_universaltime_0 bif erlang:universaltime_to_localtime/1 bif 'erl.util.date':utc_to_local/1 ebif_universaltime_to_localtime_1 bif erlang:unlink/1 bif 'erl.lang.proc':unlink/1 ebif_unlink_1 bif erlang:unregister/1 bif 'erl.lang.node':unregister/1 ebif_unregister_1 bif erlang:whereis/1 bif 'erl.lang.node':whereis/1 ebif_whereis_1 bif erlang:spawn_opt/1 bif 'erl.lang.proc':spawn_opt/1 ebif_spawn_opt_1 bif erlang:setnode/2 bif erlang:setnode/3 bif erlang:dist_exit/3 bif erlang:dist_unlink/2 bif erlang:dist_link/2 bif erlang:port_call/2 bif 'erl.lang.port':call/2 ebif_port_call_2 bif erlang:port_call/3 bif 'erl.lang.port':call/3 ebif_port_call_3 bif erlang:port_command/2 bif 'erl.lang.port':command/2 ebif_port_command_2 bif erlang:port_control/3 bif 'erl.lang.port':control/3 ebif_port_control_3 bif erlang:port_close/1 bif 'erl.lang.port':close/1 ebif_port_close_1 bif erlang:port_connect/2 bif 'erl.lang.port':connect/2 ebif_port_connect_2 bif erlang:port_set_data/2 bif 'erl.lang.port':set_data/2 ebif_port_set_data_2 bif erlang:port_get_data/1 bif 'erl.lang.port':get_data/1 ebif_port_get_data_1 # Tracing & debugging. bif erlang:trace_pattern/2 bif 'erl.system.debug':trace_pattern/2 ebif_trace_pattern_2 bif erlang:trace_pattern/3 bif 'erl.system.debug':trace_pattern/3 ebif_trace_pattern_3 bif erlang:trace/3 bif 'erl.system.debug':trace/3 ebif_trace_3 bif erlang:trace_info/2 bif 'erl.system.debug':trace_info/2 ebif_trace_info_2 bif erlang:seq_trace/2 bif 'erl.system.debug':seq_trace/2 ebif_seq_trace_2 bif erlang:seq_trace_info/1 bif 'erl.system.debug':seq_trace_info/1 ebif_seq_trace_info_1 bif erlang:seq_trace_print/1 bif 'erl.system.debug':seq_trace_print/1 ebif_seq_trace_print_1 bif erlang:seq_trace_print/2 bif 'erl.system.debug':seq_trace_print/2 ebif_seq_trace_print_2 bif erlang:suspend_process/1 bif 'erl.system.debug':suspend_process/1 ebif_suspend_process_1 bif erlang:resume_process/1 bif 'erl.system.debug':resume_process/1 ebif_resume_process_1 bif erlang:process_display/2 bif 'erl.system.debug':process_display/2 ebif_process_display_2 # Used to implemented in the erlang:info/1 BIF. bif erlang:bump_reductions/1 bif 'erl.lang.proc':bump_reductions/1 ebif_bump_reductions_1 bif math:cos/1 bif 'erl.lang.math':cos/1 ebif_math_cos_1 bif math:cosh/1 bif 'erl.lang.math':cosh/1 ebif_math_cosh_1 bif math:sin/1 bif 'erl.lang.math':sin/1 ebif_math_sin_1 bif math:sinh/1 bif 'erl.lang.math':sinh/1 ebif_math_sinh_1 bif math:tan/1 bif 'erl.lang.math':tan/1 ebif_math_tan_1 bif math:tanh/1 bif 'erl.lang.math':tanh/1 ebif_math_tanh_1 bif math:acos/1 bif 'erl.lang.math':acos/1 ebif_math_acos_1 bif math:acosh/1 bif 'erl.lang.math':acosh/1 ebif_math_acosh_1 bif math:asin/1 bif 'erl.lang.math':asin/1 ebif_math_asin_1 bif math:asinh/1 bif 'erl.lang.math':asinh/1 ebif_math_asinh_1 bif math:atan/1 bif 'erl.lang.math':atan/1 ebif_math_atan_1 bif math:atanh/1 bif 'erl.lang.math':atanh/1 ebif_math_atanh_1 bif math:erf/1 bif 'erl.lang.math':erf/1 ebif_math_erf_1 bif math:erfc/1 bif 'erl.lang.math':erfc/1 ebif_math_erfc_1 bif math:exp/1 bif 'erl.lang.math':exp/1 ebif_math_exp_1 bif math:log/1 bif 'erl.lang.math':log/1 ebif_math_log_1 bif math:log10/1 bif 'erl.lang.math':log10/1 ebif_math_log10_1 bif math:sqrt/1 bif 'erl.lang.math':sqrt/1 ebif_math_sqrt_1 bif math:atan2/2 bif 'erl.lang.math':atan2/2 ebif_math_atan2_2 bif math:pow/2 bif 'erl.lang.math':pow/2 ebif_math_pow_2 bif erlang:start_timer/3 bif 'erl.lang.timer':start/3 ebif_start_timer_3 bif erlang:send_after/3 bif 'erl.lang.timer':send_after/3 ebif_send_after_3 bif erlang:cancel_timer/1 bif 'erl.lang.timer':cancel/1 ebif_cancel_timer_1 bif erlang:read_timer/1 bif 'erl.lang.timer':read/1 ebif_read_timer_1 bif erlang:make_tuple/2 bif 'erl.lang.tuple':make/2 ebif_make_tuple_2 bif erlang:append_element/2 bif 'erl.lang.tuple':append_element/2 ebif_append_element_2 bif erlang:system_flag/2 bif 'erl.system':set_flag/2 ebif_system_flag_2 bif erlang:system_info/1 bif 'erl.system':info/1 ebif_system_info_1 # New in R9C bif erlang:system_monitor/0 bif 'erl.system':monitor/0 ebif_system_monitor_0 bif erlang:system_monitor/1 bif 'erl.system':monitor/1 ebif_system_monitor_1 bif erlang:system_monitor/2 bif 'erl.system':monitor/2 ebif_system_monitor_2 bif erlang:ref_to_list/1 bif 'erl.lang.ref':to_string/1 ebif_ref_to_string_1 ref_to_list_1 bif erlang:port_to_list/1 bif 'erl.lang.port':to_string/1 ebif_port_to_string_1 port_to_list_1 bif erlang:fun_to_list/1 bif 'erl.lang.function':to_string/1 ebif_fun_to_string_1 fun_to_list_1 bif erlang:monitor/2 bif 'erl.lang.proc':monitor/2 ebif_monitor_2 bif erlang:demonitor/1 bif 'erl.lang.proc':demonitor/1 ebif_demonitor_1 bif erlang:is_process_alive/1 bif 'erl.lang.proc':is_alive/1 ebif_proc_is_alive_1 is_process_alive_1 bif erlang:fault/1 bif 'erl.lang':error/1 ebif_error_1 fault_1 bif erlang:fault/2 bif 'erl.lang':error/2 ebif_error_2 fault_2 bif erlang:is_builtin/3 bif 'erl.system.code':is_builtin/3 ebif_is_builtin_3 ubif erlang:'and'/2 ubif 'erl.lang.bool':'and'/2 ebif_and_2 ubif erlang:'or'/2 ubif 'erl.lang.bool':'or'/2 ebif_or_2 ubif erlang:'xor'/2 ubif 'erl.lang.bool':'xor'/2 ebif_xor_2 ubif erlang:'not'/1 ubif 'erl.lang.bool':'not'/1 ebif_not_1 ubif erlang:'>'/2 sgt_2 ubif 'erl.lang.term':greater/2 ebif_gt_2 sgt_2 ubif erlang:'>='/2 sge_2 ubif 'erl.lang.term':greater_or_equal/2 ebif_ge_2 sge_2 ubif erlang:'<'/2 slt_2 ubif 'erl.lang.term':less/2 ebif_lt_2 slt_2 ubif erlang:'=<'/2 sle_2 ubif 'erl.lang.term':less_or_equal/2 ebif_le_2 sle_2 ubif erlang:'=:='/2 seq_2 ubif 'erl.lang.term':equal/2 ebif_eq_2 seq_2 ubif erlang:'=='/2 seqeq_2 ubif 'erl.lang.term':arith_equal/2 ebif_areq_2 seqeq_2 ubif erlang:'=/='/2 sneq_2 ubif 'erl.lang.term':not_equal/2 ebif_neq_2 sneq_2 ubif erlang:'/='/2 sneqeq_2 ubif 'erl.lang.term':not_arith_equal/2 ebif_nareq_2 sneqeq_2 ubif erlang:'+'/2 splus_2 ubif 'erl.lang.number':plus/2 ebif_plus_2 splus_2 ubif erlang:'-'/2 sminus_2 ubif 'erl.lang.number':minus/2 ebif_minus_2 sminus_2 ubif erlang:'*'/2 stimes_2 ubif 'erl.lang.number':multiply/2 ebif_multiply_2 stimes_2 ubif erlang:'/'/2 div_2 ubif 'erl.lang.number':divide/2 ebif_divide_2 div_2 ubif erlang:'div'/2 intdiv_2 ubif 'erl.lang.integer':'div'/2 ebif_intdiv_2 ubif erlang:'rem'/2 ubif 'erl.lang.integer':'rem'/2 ebif_rem_2 ubif erlang:'bor'/2 ubif 'erl.lang.integer':'bor'/2 ebif_bor_2 ubif erlang:'band'/2 ubif 'erl.lang.integer':'band'/2 ebif_band_2 ubif erlang:'bxor'/2 ubif 'erl.lang.integer':'bxor'/2 ebif_bxor_2 ubif erlang:'bsl'/2 ubif 'erl.lang.integer':'bsl'/2 ebif_bsl_2 ubif erlang:'bsr'/2 ubif 'erl.lang.integer':'bsr'/2 ebif_bsr_2 ubif erlang:'bnot'/1 ubif 'erl.lang.integer':'bnot'/1 ebif_bnot_1 ubif erlang:'-'/1 sminus_1 ubif 'erl.lang.number':minus/1 ebif_minus_1 sminus_1 ubif erlang:'+'/1 splus_1 ubif 'erl.lang.number':plus/1 ebif_plus_1 splus_1 # New operators in R8. These were the only operators missing. # erlang:send/2, erlang:append/2 and erlang:subtract/2 are now also # defined in erlang.erl, and the C names can be removed when all # internal references have been updated to the new ebif_... entries. bif erlang:'!'/2 ebif_bang_2 bif 'erl.lang':send/2 ebif_send_2 send_2 bif erlang:send/2 bif 'erl.lang':send/3 ebif_send_3 send_3 bif erlang:send/3 bif erlang:'++'/2 ebif_plusplus_2 bif 'erl.lang.list':append/2 ebif_append_2 ebif_plusplus_2 bif erlang:append/2 bif erlang:'--'/2 ebif_minusminus_2 bif 'erl.lang.list':subtract/2 ebif_list_subtract_2 ebif_minusminus_2 bif erlang:subtract/2 ubif erlang:is_atom/1 ubif 'erl.lang.term':is_atom/1 ebif_is_atom_1 ubif erlang:is_list/1 ubif 'erl.lang.term':is_list/1 ebif_is_list_1 ubif erlang:is_tuple/1 ubif 'erl.lang.term':is_tuple/1 ebif_is_tuple_1 ubif erlang:is_constant/1 ubif 'erl.lang.term':is_constant/1 ebif_is_constant_1 ubif erlang:is_float/1 ubif 'erl.lang.term':is_float/1 ebif_is_float_1 ubif erlang:is_integer/1 ubif 'erl.lang.term':is_integer/1 ebif_is_integer_1 ubif erlang:is_number/1 ubif 'erl.lang.term':is_number/1 ebif_is_number_1 ubif erlang:is_pid/1 ubif 'erl.lang.term':is_pid/1 ebif_is_pid_1 ubif erlang:is_port/1 ubif 'erl.lang.term':is_port/1 ebif_is_port_1 ubif erlang:is_reference/1 ubif 'erl.lang.term':is_reference/1 ebif_is_reference_1 ubif erlang:is_binary/1 ubif 'erl.lang.term':is_binary/1 ebif_is_binary_1 ubif erlang:is_function/1 ubif 'erl.lang.term':is_function/1 ebif_is_function_1 ubif erlang:is_record/3 ubif 'erl.lang.term':is_record/3 ebif_is_record_3 bif erlang:match_spec_test/3 bif erlang:'$put'/2 dollar_put_2 bif erlang:'$get'/0 dollar_get_0 bif erlang:'$get'/1 dollar_get_1 bif erlang:'$get_keys'/1 dollar_get_keys_1 bif erlang:'$erase'/0 dollar_erase_0 bif erlang:'$erase'/1 dollar_erase_1 # # Bifs in ets module. # bif ets:all/0 bif 'erl.lang.ets':all/0 ebif_ets_all_0 bif ets:new/2 bif 'erl.lang.ets':new/2 ebif_ets_new_2 bif ets:db_delete/1 bif 'erl.lang.ets':db_delete/1 ebif_ets_db_delete_1 bif ets:delete/2 bif 'erl.lang.ets':delete/2 ebif_ets_delete_2 bif ets:delete_all_objects/1 bif 'erl.lang.ets':delete_all_objects/1 ebif_ets_delete_all_objects_1 bif ets:delete_object/2 bif 'erl.lang.ets':delete_object/2 ebif_ets_delete_object_2 bif ets:first/1 bif 'erl.lang.ets':first/1 ebif_ets_first_1 bif ets:fixtable/2 bif 'erl.lang.ets':fixtable/2 ebif_ets_fixtable_2 bif ets:lookup/2 bif 'erl.lang.ets':lookup/2 ebif_ets_lookup_2 bif ets:lookup_element/3 bif 'erl.lang.ets':lookup_element/3 ebif_ets_lookup_element_3 bif ets:db_info/2 bif 'erl.lang.ets':db_info/2 ebif_ets_db_info_2 bif ets:last/1 bif 'erl.lang.ets':last/1 ebif_ets_last_1 bif ets:match/1 bif 'erl.lang.ets':match/1 ebif_ets_match_1 bif ets:match/2 bif 'erl.lang.ets':match/2 ebif_ets_match_2 bif ets:match/3 bif 'erl.lang.ets':match/3 ebif_ets_match_3 bif ets:match_object/1 bif 'erl.lang.ets':match_object/1 ebif_ets_match_object_1 bif ets:match_object/2 bif 'erl.lang.ets':match_object/2 ebif_ets_match_object_2 bif ets:match_object/3 bif 'erl.lang.ets':match_object/3 ebif_ets_match_object_3 bif ets:member/2 bif 'erl.lang.ets':member/2 ebif_ets_member_2 bif ets:next/2 bif 'erl.lang.ets':next/2 ebif_ets_next_2 bif ets:prev/2 bif 'erl.lang.ets':prev/2 ebif_ets_prev_2 bif ets:insert/2 bif 'erl.lang.ets':insert/2 ebif_ets_insert_2 bif ets:rename/2 bif 'erl.lang.ets':rename/2 ebif_ets_rename_2 bif ets:safe_fixtable/2 bif 'erl.lang.ets':safe_fixtable/2 ebif_ets_safe_fixtable_2 bif ets:slot/2 bif 'erl.lang.ets':slot/2 ebif_ets_slot_2 bif ets:update_counter/3 bif 'erl.lang.ets':update_counter/3 ebif_ets_update_counter_3 bif ets:select/1 bif 'erl.lang.ets':select/1 ebif_ets_select_1 bif ets:select/2 bif 'erl.lang.ets':select/2 ebif_ets_select_2 bif ets:select/3 bif 'erl.lang.ets':select/3 ebif_ets_select_3 bif ets:select_count/2 bif 'erl.lang.ets':select/2 ebif_ets_select_count_2 bif ets:select_reverse/1 bif 'erl.lang.ets':select_reverse/1 ebif_ets_select_reverse_1 bif ets:select_reverse/2 bif 'erl.lang.ets':select_reverse/2 ebif_ets_select_reverse_2 bif ets:select_reverse/3 bif 'erl.lang.ets':select_reverse/3 ebif_ets_select_reverse_3 bif ets:select_delete/2 bif 'erl.lang.ets':select_delete/2 ebif_ets_select_delete_2 bif ets:match_spec_compile/1 bif 'erl.lang.ets':match_spec_compile/1 ebif_ets_match_spec_compile_1 bif ets:match_spec_run/2 bif 'erl.lang.ets':match_spec_run/2 ebif_ets_match_spec_run_2 bif ets:match_spec_run/3 bif 'erl.lang.ets':match_spec_run/3 ebif_ets_match_spec_run_3 # # Bifs in os module. # bif os:putenv/2 bif 'erl.system.os':putenv/2 ebif_os_putenv_2 bif os:getenv/0 bif 'erl.system.os':getenv/0 ebif_os_getenv_0 bif os:getenv/1 bif 'erl.system.os':getenv/1 ebif_os_getenv_1 bif os:getpid/0 bif 'erl.system.os':getpid/0 ebif_os_getpid_0 # # Bifs in lists module. # bif lists:member/2 bif 'erl.lang.list':is_element/2 ebif_list_is_element_2 lists_member_2 bif lists:reverse/2 bif 'erl.lang.list':reverse/2 ebif_list_reverse_2 lists_reverse_2 bif lists:keymember/3 bif 'erl.lang.list.keylist':is_element/3 ebif_keylist_is_element_3 lists_keymember_3 bif lists:keysearch/3 bif 'erl.lang.list.keylist':search/3 ebif_keylist_search_3 lists_keysearch_3 # # Vector bifs. # bif vector:new/2 bif 'erl.lang.vector':new/2 ebif_vector_new_2 bif vector:from_list/1 bif 'erl.lang.vector':from_list/1 ebif_vector_from_list_1 bif vector:to_list/2 bif 'erl.lang.vector':to_list/2 ebif_vector_to_list_2 bif vector:get/2 bif 'erl.lang.vector':get/2 ebif_vector_get_2 bif vector:set/3 bif 'erl.lang.vector':set/3 ebif_vector_set_3 # # Bifs for debugging. # bif erts_debug:disassemble/1 bif 'erl.system.debug':disassemble/1 ebif_erts_debug_disassemble_1 bif erts_debug:make_fun/1 bif 'erl.system.debug':make_fun/1 ebif_erts_debug_make_fun_1 bif erts_debug:breakpoint/2 bif 'erl.system.debug':breakpoint/2 ebif_erts_debug_breakpoint_2 bif erts_debug:same/2 bif 'erl.system.debug':same/2 ebif_erts_debug_same_2 bif erts_debug:flat_size/1 bif 'erl.system.debug':flat_size/1 ebif_erts_debug_flat_size_1 # There is also a pseudo-BIF named erts_debug:apply/4. # # New Bifs in R8. # bif code:get_chunk/2 bif 'erl.lang.code':get_chunk/2 ebif_code_get_chunk_2 bif code:module_md5/1 bif 'erl.lang.code':module_md5/1 ebif_code_module_md5_1 bif code:make_stub_module/3 bif 'erl.lang.code':make_stub_module/3 ebif_code_make_stub_module_3 bif code:is_module_native/1 bif 'erl.lang.code':is_native_module/1 ebif_code_is_native_module_1 code_is_module_native_1 bif erlang:blocking_read_file/1 # # New Bifs in R9C. # bif erlang:hibernate/3 bif error_logger:warning_map/0 From luke@REDACTED Mon Sep 15 15:16:31 2003 From: luke@REDACTED (Luke Gorrie) Date: 15 Sep 2003 15:16:31 +0200 Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: <001101c37b64$ec01e8c0$b701010a@lamppc36> References: <001101c37b64$ec01e8c0$b701010a@lamppc36> Message-ID: "Erik Stenman" writes: > Hence you are faced with three options: > 1. Reimplement all the BIFs yourself to work with your system. > It is a major undertaking to get all of them working (If > you take a look at other Erlang implementations (e.g., ETOS > and Gerl) you will see that it is in the support of all these > BIFs that these systems lack. It just takes to much time to > reimplement all this and get it bug free. This may well be the understatement of the century, but: is it really so much work? :-) It "seems" like most of it should be quite easy in an ETOS-like implementation. It should be mostly wrappers for: numbers and maths, lists, vectors, garbage collection. Processes are free in the sense that they're fun rather than work :-). That leaves basically ETS, code loading, ports, debugging, and some miscellany. I can certainly believe it's hard, but I wouldn't have thought it so much harder than the HiPE approach? I must emphasise that I'm not pretending to know that it isn't harder, I'm just saying that in my stupidly brief perusal I don't understand why it is :-) Also I think the real reason ETOS is so incomplete is that they weren't aiming to do a full implementation, rather they focused on a minimal one for running benchmark'ey programs. That's how it looks in the version they distribute sources to at least -- e.g. they skipped implementing EXIT signals even though they're ultra-fundamental and not difficult to implement. (BTW, Does anyone know why the ETOS guys only distribute the source to version 1.4 even though they have binaries of version 2.3 up? They don't answer my mail..) Aside from the BIFs, another issue is linked in drivers. Do you know how separable those are? In practice do you need to link some of them with BEAM'ey libraries or similar? Cheers, Luke From joachim.durchholz@REDACTED Mon Sep 15 16:13:59 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Mon, 15 Sep 2003 16:13:59 +0200 Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: <001101c37b64$ec01e8c0$b701010a@lamppc36> References: <001101c37b64$ec01e8c0$b701010a@lamppc36> Message-ID: <3F65C927.6050803@web.de> Erik Stenman wrote: > For your reference, here are some BIFs you would have to implement to > be compatible with R9 (remember that you need to support bignum and > floating-point arithmetic also): > [snipped] Taking the list, breaking lines at every tab, sorting it and disregarding anything that didn't start with "bif" or "ubif", this gave me 531 bifs (532 if you count the duplicate entry in). I agree that's quite a lot... Regards, Jo From crav@REDACTED Mon Sep 15 11:39:59 2003 From: crav@REDACTED (=?iso-8859-1?Q?Carlos_Rodr=EDguez_Alcal=E1_Villagra?=) Date: Mon, 15 Sep 2003 11:39:59 +0200 Subject: MEGACO commnads structures Message-ID: <002a01c37b6d$544f4a00$6600a8c0@carlos> Hi there, I have seen that the structures used for the MEGACO commands are defined inside the archive "megaco.hrl". But, I could not find all the structures related to the MEGACO commands. The ones I found are SubtractRequest, NotifyRequest and ServiceChangeRequest. Where are the others? I guess that probably they are all there but I couldn't find it because (maybe) they have a different name. Is there any documentation about these structures and the usage of the commands? Any help is welcome, I am really in a hurry here. Farewell, Carlos R. A. -------------- next part -------------- An HTML attachment was scrubbed... URL: From erlang@REDACTED Mon Sep 15 18:19:07 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Mon, 15 Sep 2003 17:19:07 +0100 Subject: MEGACO commnads structures In-Reply-To: <002a01c37b6d$544f4a00$6600a8c0@carlos> References: <002a01c37b6d$544f4a00$6600a8c0@carlos> Message-ID: <3F65E67B.9040802@manderp.freeserve.co.uk> Quick answer: Have a look in megaco_message_v1.hrl it contains many more record definitions. A longer answer may follow, depending on my free time. Pete. Carlos Rodr?guez Alcal? Villagra wrote: > > Hi there, > I have seen that the structures used for the MEGACO commands are defined > inside the archive "megaco.hrl". But, I could not find all the > structures related to the MEGACO commands. The ones I found are > SubtractRequest, NotifyRequest and ServiceChangeRequest. > Where are the others? I guess that probably they are all there but I > couldn't find it because (maybe) they have a different name. > Is there any documentation about these structures and the usage of the > commands? > Any help is welcome, I am really in a hurry here. > > Farewell, > Carlos R. A. From ingela@REDACTED Mon Sep 15 18:42:18 2003 From: ingela@REDACTED (Ingela Anderton) Date: Mon, 15 Sep 2003 18:42:18 +0200 Subject: ODBC connection fails References: <16224.30832.258844.423969@gargle.gargle.HOWL> <16225.34841.799469.184632@gargle.gargle.HOWL> <16225.56585.998213.279895@gargle.gargle.HOWL> Message-ID: <16229.60394.478291.301625@gargle.gargle.HOWL> Vlad Dumitrescu wrote: > What misguided me was the following statement (my emphasis) > > > "Alas some drivers only support sequential traversal of the result > > set, e.i. they do not support what in the ODBC world is known as > > scrollable cursors. This will have the effect that functions such as > > first/[1,2], last/[1,2], prev[1,2], etc ***may*** return {error, > > driver_does_not_support_function}" > > Maybe it's only my bad English, but "may" implies that it also "may > not". Hummm... the thought behind that was that the functions may return an error instead of the expected result if you use a driver that does not support scrollable cursors. I will consider changing the phrasing to avoid further confusion. > Thanks again, and now I know that I can use odbc:next without first calling > odbc:first (which wasn't obvious to me, but reading the documentation very > carefully, one can deduce it) Thanks for the input we will try to make it more obvious in the future. -- /Ingela Ericsson AB - OTP team From per.gustafsson@REDACTED Mon Sep 15 12:48:23 2003 From: per.gustafsson@REDACTED (Per Gustafsson) Date: Mon, 15 Sep 2003 12:48:23 +0200 (MEST) Subject: Build problem with R9C-0 In-Reply-To: <3F655B4A.4070506@eth.ericsson.se> References: <3F655B4A.4070506@eth.ericsson.se> Message-ID: This problem seems to have to do with the shared heap. It seems that you get the hipe_literals.hrl file that is produced when making the shared emulator. I think you can solve this problem by changing your: erts/emulator/hipe/hipe_mkliterals.c and lib/hipe/rtl/hipe_tagscheme.erl to the ones I've attached to this mail. On Mon, 15 Sep 2003, Zoltan Peter Toth wrote: > Hi, > > Can anybody advise me what's wrong with my build: > (it's Debian Linux, gcc 3.0 [but 2.95 does the same]. I attached my config.cache.) > > ---------- > === Entering application hipe > make[3]: Entering directory `.../otp_src_R9C-0/lib/hipe/rtl' > erlc -W -bbeam +debug_info -o../ebin hipe_rtl.erl > erlc -W -bbeam +debug_info -o../ebin hipe_rtl_cfg.erl > erlc -W -bbeam +debug_info -o../ebin hipe_rtl_cse.erl > erlc -W -bbeam +debug_info -o../ebin hipe_rtl_ebb.erl > erlc -W -bbeam +debug_info -o../ebin hipe_rtl_liveness.erl > erlc -W -bbeam +debug_info -o../ebin hipe_rtl_prop.erl > erlc -W -bbeam +debug_info -o../ebin hipe_icode2rtl.erl > erlc -W -bbeam +debug_info -o../ebin hipe_tagscheme.erl > ./otp_src_R9C-0/lib/hipe/rtl/hipe_tagscheme.erl:695: undefined macro ''P_OFF_HEAP_OVERHEAD'' > ./otp_src_R9C-0/lib/hipe/rtl/hipe_tagscheme.erl:37: function finalize_bin/4 undefined > --------- > (The latter error is a consequence of the former, as it wants to export the erroneous function.) > > And really, the string P_OFF_HEAP_OVERHEAD was not found in the whole source tree > with a recursive egrep. > Of course, hipe does not work. > Thanks for any advice. > Zoltan > -------------- next part -------------- %%% $Id: hipe_tagscheme.erl,v 1.23 2003/07/10 12:52:36 pergu Exp $ %%% %%% hipe_tagscheme.erl %%% %%% XXX: This is specific for Erlang 5.0 / R9. %%% %%% 020904: Happi - added support for external pids and ports. %%% -module(hipe_tagscheme). -export([mk_nil/0, mk_fixnum/1, mk_arityval/1, mk_atom/1, mk_non_value/0]). -export([is_fixnum/1]). -export([tag_bignum/2, tag_flonum/2, tag_tuple/2, tag_cons/2]). -export([write_catch_frame/3]). -export([save_CP/4, restore_CP/4]). -export([test_is_boxed/4, get_header/2]). -export([test_nil/4, test_cons/4, test_flonum/4, test_fixnum/4, test_tuple/4, test_atom/4, test_bignum/4, test_any_pid/4,test_any_port/4, test_internal_pid/4, test_internal_port/4, test_ref/4, test_fun/4, test_binary/4, test_list/4, test_integer/4, test_number/4, test_constant/4, test_tuple_N/5]). -export([untag_fixnum/2]). -export([test_two_fixnums/3, fixnum_gt/5, fixnum_lt/5, fixnum_ge/5, fixnum_le/5, fixnum_addsub/5, fixnum_mul/4, fixnum_andorxor/4, fixnum_not/2]). -export([unsafe_car/2, unsafe_cdr/2, unsafe_constant_element/3, unsafe_update_element/3, element/6]). -export([unsafe_closure_element/3]). -export([mk_fun_header/0, tag_fun/2, untag_fun/2, if_fun_get_arity_and_address/5]). -export([unsafe_untag_float/2, unsafe_tag_float/3]). -export([unsafe_mk_sub_binary/4, unsafe_mk_float/3, unsafe_mk_big/4, unsafe_load_float/3]). -export([test_subbinary/3, test_heap_binary/3]). -export([finalize_bin/4, mk_var_header/3, get_base/2]). -include("hipe_icode2rtl.hrl"). -include("hipe_literals.hrl"). -undef(TAG_PRIMARY_BOXED). -undef(TAG_IMMED2_MASK). -undef(TAG_IMMED2_CATCH). -undef(TAG_IMMED2_SIZE). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -define(TAG_PRIMARY_SIZE, 2). -define(TAG_PRIMARY_MASK, 16#3). -define(TAG_PRIMARY_HEADER, 16#0). -define(TAG_PRIMARY_LIST, 16#1). -define(TAG_PRIMARY_BOXED, 16#2). -define(TAG_PRIMARY_IMMED1, 16#3). -define(TAG_IMMED1_SIZE, 4). -define(TAG_IMMED1_MASK, 16#F). -define(TAG_IMMED1_PID, ((16#0 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_IMMED1)). -define(TAG_IMMED1_PORT, ((16#1 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_IMMED1)). -define(TAG_IMMED1_IMMED2,((16#2 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_IMMED1)). -define(TAG_IMMED1_SMALL, ((16#3 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_IMMED1)). -define(TAG_IMMED2_SIZE, 6). -define(TAG_IMMED2_MASK, 16#3F). -define(TAG_IMMED2_ATOM, ((16#0 bsl ?TAG_IMMED1_SIZE) bor ?TAG_IMMED1_IMMED2)). -define(TAG_IMMED2_CATCH, ((16#1 bsl ?TAG_IMMED1_SIZE) bor ?TAG_IMMED1_IMMED2)). -define(TAG_IMMED2_NIL, ((16#3 bsl ?TAG_IMMED1_SIZE) bor ?TAG_IMMED1_IMMED2)). -define(TAG_HEADER_ARITYVAL,((16#0 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_VECTOR, ((16#1 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_POS_BIG, ((16#2 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_NEG_BIG, ((16#3 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(BIG_SIGN_BIT, (16#1 bsl ?TAG_PRIMARY_SIZE)). -define(TAG_HEADER_REF, ((16#4 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_FUN, ((16#5 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_FLOAT, ((16#6 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(BINARY_XXX_MASK, (16#3 bsl ?TAG_PRIMARY_SIZE)). -define(TAG_HEADER_REFC_BIN,((16#8 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_HEAP_BIN,((16#9 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_SUB_BIN, ((16#A bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_EXTERNAL_PID, ((16#C bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_EXTERNAL_PORT,((16#D bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_EXTERNAL_REF, ((16#E bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_MASK, 16#3F). -define(HEADER_ARITY_OFFS, 6). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% mk_header(SZ,TAG) -> (SZ bsl ?HEADER_ARITY_OFFS) + TAG. mk_arityval(SZ) -> mk_header(SZ, ?TAG_HEADER_ARITYVAL). mk_fixnum(X) -> (X bsl ?TAG_IMMED1_SIZE) + ?TAG_IMMED1_SMALL. -define(NIL, ((-1 bsl ?TAG_IMMED2_SIZE) bor ?TAG_IMMED2_NIL)). mk_nil() -> ?NIL. mk_atom(X) -> (X bsl ?TAG_IMMED2_SIZE) + ?TAG_IMMED2_ATOM. mk_non_value() -> ?THE_NON_VALUE. -define(SMALL_BITS, 28). -define(MAX_SMALL, ((1 bsl (?SMALL_BITS - 1)) - 1)). -define(MIN_SMALL, (-(1 bsl (?SMALL_BITS - 1)))). is_fixnum(N) when N =< ?MAX_SMALL, N >= ?MIN_SMALL -> true; is_fixnum(_) -> false. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -define(HEADER_FUN, mk_header(?ERL_FUN_SIZE-2,?TAG_HEADER_FUN)). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% tag_boxed(Res, X) -> hipe_rtl:mk_alu(Res, X, 'add', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)). tag_bignum(Res, X) -> tag_boxed(Res, X). tag_flonum(Res, X) -> tag_boxed(Res, X). tag_tuple(Res, X) -> tag_boxed(Res, X). tag_cons(Res, X) -> hipe_rtl:mk_alu(Res, X, 'add', hipe_rtl:mk_imm(?TAG_PRIMARY_LIST)). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% write_catch_frame(SP, Off, CatchLab) -> %% SP[Off] = make_catch(CatchLab) %% loader should transform the label to a catch table index, %% tag it, and emit a 'load constant' insn CatchPC = hipe_rtl:mk_new_reg(), [hipe_rtl:mk_load_address(CatchPC, CatchLab, 'catch'), hipe_rtl:mk_store(SP, hipe_rtl:mk_imm(Off), CatchPC)]. %%% no longer needed %tag_catch(Ix) -> (Ix bsl ?TAG_IMMED2_SIZE) bor ?TAG_IMMED2_CATCH. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% This is safe for SPARC and other RISCs, which always create 32-bit %%% aligned return addresses. %%% For the x86, we assume that either CALL insns are aligned to ensure %%% 32-bit aligned return addresses, or that stack/register maps are %%% generated to inform the gc which words contain return addresses. %%% %%% XXX: this is trivial now -- inline at call sites? save_CP(CP, SP, Off, Code) -> [hipe_rtl:mk_store(SP, Off, CP) | Code]. restore_CP(CP, SP, Off, Code) -> [hipe_rtl:mk_load(CP, SP, Off) | Code]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Operations to test if an object has a known type T. test_nil(X, TrueLab, FalseLab, Pred) -> hipe_rtl:mk_branch(X, eq, hipe_rtl:mk_imm(?NIL), TrueLab, FalseLab, Pred). test_cons(X, TrueLab, FalseLab, Pred) -> Tmp = hipe_rtl:mk_new_reg(), Mask = hipe_rtl:mk_imm(?TAG_PRIMARY_MASK - ?TAG_PRIMARY_LIST), hipe_rtl:mk_alub(Tmp, X, 'and', Mask, 'eq', TrueLab, FalseLab, Pred). test_is_boxed(X, TrueLab, FalseLab, Pred) -> Tmp = hipe_rtl:mk_new_reg(), Mask = hipe_rtl:mk_imm(?TAG_PRIMARY_MASK - ?TAG_PRIMARY_BOXED), hipe_rtl:mk_alub(Tmp, X, 'and', Mask, 'eq', TrueLab, FalseLab, Pred). get_header(Res, X) -> hipe_rtl:mk_load(Res, X, hipe_rtl:mk_imm(-(?TAG_PRIMARY_BOXED))). mask_and_compare(X, Mask, Value, TrueLab, FalseLab, Pred) -> Tmp = hipe_rtl:mk_new_reg(), [hipe_rtl:mk_alu(Tmp, X, 'and', hipe_rtl:mk_imm(Mask)), hipe_rtl:mk_branch(Tmp, 'eq', hipe_rtl:mk_imm(Value), TrueLab, FalseLab, Pred)]. test_immed1(X, Value, TrueLab, FalseLab, Pred) -> mask_and_compare(X, ?TAG_IMMED1_MASK, Value, TrueLab, FalseLab, Pred). test_internal_pid(X, TrueLab, FalseLab, Pred) -> test_immed1(X, ?TAG_IMMED1_PID, TrueLab, FalseLab, Pred). test_any_pid(X, TrueLab, FalseLab, Pred) -> NotInternalPidLab = hipe_rtl:mk_new_label(), [test_internal_pid(X, TrueLab, hipe_rtl:label_name(NotInternalPidLab), Pred), NotInternalPidLab, test_external_pid(X, TrueLab,FalseLab,Pred)]. test_external_pid(X, TrueLab, FalseLab, Pred) -> Tmp = hipe_rtl:mk_new_reg(), HalfTrueLab = hipe_rtl:mk_new_label(), ExternalPidMask = ?TAG_HEADER_MASK, [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred), HalfTrueLab, get_header(Tmp, X), mask_and_compare(Tmp, ExternalPidMask, ?TAG_HEADER_EXTERNAL_PID, TrueLab, FalseLab, Pred)]. test_internal_port(X, TrueLab, FalseLab, Pred) -> test_immed1(X, ?TAG_IMMED1_PORT, TrueLab, FalseLab, Pred). test_any_port(X, TrueLab, FalseLab, Pred) -> NotInternalPortLab = hipe_rtl:mk_new_label(), [test_internal_port(X, TrueLab, hipe_rtl:label_name(NotInternalPortLab), Pred), NotInternalPortLab, test_external_port(X, TrueLab,FalseLab,Pred)]. test_external_port(X, TrueLab, FalseLab, Pred) -> Tmp = hipe_rtl:mk_new_reg(), HalfTrueLab = hipe_rtl:mk_new_label(), ExternalPortMask = ?TAG_HEADER_MASK, [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred), HalfTrueLab, get_header(Tmp, X), mask_and_compare(Tmp, ExternalPortMask, ?TAG_HEADER_EXTERNAL_PORT, TrueLab, FalseLab, Pred)]. test_fixnum(X, TrueLab, FalseLab, Pred) -> test_immed1(X, ?TAG_IMMED1_SMALL, TrueLab, FalseLab, Pred). test_atom(X, TrueLab, FalseLab, Pred) -> mask_and_compare(X, ?TAG_IMMED2_MASK, ?TAG_IMMED2_ATOM, TrueLab, FalseLab, Pred). test_tuple(X, TrueLab, FalseLab, Pred) -> Tmp = hipe_rtl:mk_new_reg(), Tmp2 = hipe_rtl:mk_new_reg(), HalfTrueLab = hipe_rtl:mk_new_label(), [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred), HalfTrueLab, get_header(Tmp, X), hipe_rtl:mk_alub(Tmp2, Tmp, 'and', hipe_rtl:mk_imm(?TAG_HEADER_MASK), 'eq', TrueLab, FalseLab, Pred)]. test_tuple_N(X, N, TrueLab, FalseLab, Pred) -> Tmp = hipe_rtl:mk_new_reg(), HalfTrueLab = hipe_rtl:mk_new_label(), [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred), HalfTrueLab, get_header(Tmp, X), hipe_rtl:mk_branch(Tmp, 'eq', hipe_rtl:mk_imm(mk_arityval(N)), TrueLab, FalseLab, Pred)]. test_ref(X, TrueLab, FalseLab, Pred) -> Tmp = hipe_rtl:mk_new_reg(), HalfTrueLab = hipe_rtl:mk_new_label(), TwoThirdsTrueLab = hipe_rtl:mk_new_label(), [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred), HalfTrueLab, get_header(Tmp, X), mask_and_compare(Tmp, ?TAG_HEADER_MASK, ?TAG_HEADER_REF, TrueLab, hipe_rtl:label_name(TwoThirdsTrueLab), Pred), TwoThirdsTrueLab, mask_and_compare(Tmp, ?TAG_HEADER_MASK, ?TAG_HEADER_EXTERNAL_REF, TrueLab, FalseLab, Pred) ]. test_fun(X, TrueLab, FalseLab, Pred) -> Tmp = hipe_rtl:mk_new_reg(), HalfTrueLab = hipe_rtl:mk_new_label(), [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred), HalfTrueLab, get_header(Tmp, X), mask_and_compare(Tmp, ?TAG_HEADER_MASK, ?TAG_HEADER_FUN, TrueLab, FalseLab, Pred)]. test_flonum(X, TrueLab, FalseLab, Pred) -> HeaderFlonum = mk_header(2, ?TAG_HEADER_FLOAT), Tmp = hipe_rtl:mk_new_reg(), HalfTrueLab = hipe_rtl:mk_new_label(), [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred), HalfTrueLab, get_header(Tmp, X), hipe_rtl:mk_branch(Tmp, 'eq', hipe_rtl:mk_imm(HeaderFlonum), TrueLab, FalseLab, Pred)]. test_bignum(X, TrueLab, FalseLab, Pred) -> Tmp = hipe_rtl:mk_new_reg(), HalfTrueLab = hipe_rtl:mk_new_label(), BigMask = ?TAG_HEADER_MASK - ?BIG_SIGN_BIT, [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred), HalfTrueLab, get_header(Tmp, X), mask_and_compare(Tmp, BigMask, ?TAG_HEADER_POS_BIG, TrueLab, FalseLab, Pred)]. test_binary(X, TrueLab, FalseLab, Pred) -> Tmp = hipe_rtl:mk_new_reg(), HalfTrueLab = hipe_rtl:mk_new_label(), Mask = ?TAG_HEADER_MASK - ?BINARY_XXX_MASK, [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred), HalfTrueLab, get_header(Tmp, X), mask_and_compare(Tmp, Mask, ?TAG_HEADER_REFC_BIN, TrueLab, FalseLab, Pred)]. test_list(X, TrueLab, FalseLab, Pred) -> Lab = hipe_rtl:mk_new_label(), [test_cons(X, TrueLab, hipe_rtl:label_name(Lab), 0.5), Lab, test_nil(X, TrueLab, FalseLab, Pred)]. test_integer(X, TrueLab, FalseLab, Pred) -> Lab = hipe_rtl:mk_new_label(), [test_fixnum(X, TrueLab, hipe_rtl:label_name(Lab), 0.5), Lab, test_bignum(X, TrueLab, FalseLab, Pred)]. test_number(X, TrueLab, FalseLab, Pred) -> Lab1 = hipe_rtl:mk_new_label(), Lab2 = hipe_rtl:mk_new_label(), Lab3 = hipe_rtl:mk_new_label(), Tmp = hipe_rtl:mk_new_reg(), BigMask = ?TAG_HEADER_MASK - ?BIG_SIGN_BIT, HeaderFlonum = mk_header(2, ?TAG_HEADER_FLOAT), [test_fixnum(X, TrueLab, hipe_rtl:label_name(Lab1), 0.5), Lab1, test_is_boxed(X, hipe_rtl:label_name(Lab2), FalseLab, 0.5), Lab2, get_header(Tmp, X), mask_and_compare(Tmp, BigMask, ?TAG_HEADER_POS_BIG, TrueLab, hipe_rtl:label_name(Lab3), 0.5), Lab3, hipe_rtl:mk_branch(Tmp, 'eq', hipe_rtl:mk_imm(HeaderFlonum), TrueLab, FalseLab, Pred)]. %%% CONS, NIL, and TUPLE are not constants, everything else is test_constant(X, TrueLab, FalseLab, Pred) -> Lab1 = hipe_rtl:mk_new_label(), Lab2 = hipe_rtl:mk_new_label(), Pred1 = 1-Pred, [test_cons(X, FalseLab, hipe_rtl:label_name(Lab1), Pred1), Lab1, test_nil(X, FalseLab, hipe_rtl:label_name(Lab2), Pred1), Lab2, test_tuple(X, FalseLab, TrueLab, Pred1)]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% untag_fixnum(DestReg, SrcVar) -> hipe_rtl:mk_alu(DestReg, SrcVar, 'sra', hipe_rtl:mk_imm(?TAG_IMMED1_SIZE)). test_two_fixnums(Arg1, Arg2, FalseLab) -> Tmp = hipe_rtl:mk_new_reg(), TrueLab = hipe_rtl:mk_new_label(), [hipe_rtl:mk_alu(Tmp, Arg1, 'and', Arg2), test_fixnum(Tmp, hipe_rtl:label_name(TrueLab), FalseLab, 0.99), TrueLab]. fixnum_cmp(Arg1, Arg2, TrueLab, FalseLab, Pred, CmpOp) -> hipe_rtl:mk_branch(Arg1, CmpOp, Arg2, TrueLab, FalseLab, Pred). fixnum_gt(Arg1, Arg2, TrueLab, FalseLab, Pred) -> fixnum_cmp(Arg1, Arg2, TrueLab, FalseLab, Pred, gt). fixnum_lt(Arg1, Arg2, TrueLab, FalseLab, Pred) -> fixnum_cmp(Arg1, Arg2, TrueLab, FalseLab, Pred, lt). fixnum_ge(Arg1, Arg2, TrueLab, FalseLab, Pred) -> fixnum_cmp(Arg1, Arg2, TrueLab, FalseLab, Pred, ge). fixnum_le(Arg1, Arg2, TrueLab, FalseLab, Pred) -> fixnum_cmp(Arg1, Arg2, TrueLab, FalseLab, Pred, le). %%% (16X+tag)+((16Y+tag)-tag) = 16X+tag+16Y = 16(X+Y)+tag %%% (16X+tag)-((16Y+tag)-tag) = 16X+tag-16Y = 16(X-Y)+tag fixnum_addsub(AluOp, Arg1, Arg2, Res, OtherLab) -> Tmp = hipe_rtl:mk_new_reg(), %% XXX: Consider moving this test to the users of fixnum_addsub. case Arg1 =/= Res andalso Arg2 =/= Res of true -> %% Args differ from res. NoOverflowLab = hipe_rtl:mk_new_label(), [hipe_rtl:mk_alu(Tmp, Arg2, sub, hipe_rtl:mk_imm(?TAG_IMMED1_SMALL)), hipe_rtl:mk_alub(Res, Arg1, AluOp, Tmp, overflow, hipe_rtl:label_name(OtherLab), hipe_rtl:label_name(NoOverflowLab), 0.01), NoOverflowLab]; false -> %% At least one of the arguments is the same as Res. Tmp2 = hipe_rtl:mk_new_var(), NoOverflowLab = hipe_rtl:mk_new_label(), [hipe_rtl:mk_alu(Tmp, Arg2, sub, hipe_rtl:mk_imm(?TAG_IMMED1_SMALL)), hipe_rtl:mk_alub(Tmp2, Arg1, AluOp, Tmp, overflow, hipe_rtl:label_name(OtherLab), hipe_rtl:label_name(NoOverflowLab), 0.01), NoOverflowLab, hipe_rtl:mk_move(Res, Tmp2)] end. %%% ((16X+tag) div 16) * ((16Y+tag)-tag) + tag = X*16Y+tag = 16(XY)+tag fixnum_mul(Arg1, Arg2, Res, OtherLab) -> Tmp = hipe_rtl:mk_new_reg(), U1 = hipe_rtl:mk_new_reg(), U2 = hipe_rtl:mk_new_reg(), NoOverflowLab = hipe_rtl:mk_new_label(), [hipe_rtl:mk_alu(U1, Arg1, 'sra', hipe_rtl:mk_imm(?TAG_IMMED1_SIZE)), hipe_rtl:mk_alu(U2, Arg2, 'sub', hipe_rtl:mk_imm(?TAG_IMMED1_SMALL)), hipe_rtl:mk_alub(Tmp, U1, 'mul', U2, overflow, hipe_rtl:label_name(OtherLab), hipe_rtl:label_name(NoOverflowLab), 0.01), NoOverflowLab, hipe_rtl:mk_alu(Res, Tmp, 'add', hipe_rtl:mk_imm(?TAG_IMMED1_SMALL))]. fixnum_andorxor(AluOp, Arg1, Arg2, Res) -> case AluOp of 'xor' -> Tmp = hipe_rtl:mk_new_reg(), [hipe_rtl:mk_alu(Tmp, Arg1, 'xor', Arg2), % clears tag :-( hipe_rtl:mk_alu(Res, Tmp, 'or', hipe_rtl:mk_imm(?TAG_IMMED1_SMALL))]; _ -> hipe_rtl:mk_alu(Res, Arg1, AluOp, Arg2) end. fixnum_not(Arg, Res) -> Mask = (-1 bsl ?TAG_IMMED1_SIZE), hipe_rtl:mk_alu(Res, Arg, 'xor', hipe_rtl:mk_imm(Mask)). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% unsafe_car(Dst, Arg) -> hipe_rtl:mk_load(Dst, Arg, hipe_rtl:mk_imm(-(?TAG_PRIMARY_LIST))). unsafe_cdr(Dst, Arg) -> hipe_rtl:mk_load(Dst, Arg, hipe_rtl:mk_imm(-(?TAG_PRIMARY_LIST)+4)). unsafe_constant_element(Dst, Index, Tuple) -> % Index is an immediate Offset = -(?TAG_PRIMARY_BOXED) + 4 * hipe_rtl:imm_value(Index), hipe_rtl:mk_load(Dst, Tuple, hipe_rtl:mk_imm(Offset)). unsafe_update_element(Tuple, Index, Value) -> % Index is an immediate Offset = -(?TAG_PRIMARY_BOXED) + 4 * hipe_rtl:imm_value(Index), hipe_rtl:mk_store(Tuple, hipe_rtl:mk_imm(Offset), Value). %%% wrong semantics % unsafe_variable_element(Dst, Index, Tuple) -> % Index is an unknown fixnum % %% Load word at (Tuple - 2) + ((Index >> 4) << 2). % %% Offset = ((Index >> 4) << 2) - 2. % %% Index = x..x1111 (fixnum tag is 2#1111). % %% (Index >> 2) = 00x..x11 and ((Index >> 4) << 2) = 00x..x00. % %% Therefore, ((Index >> 4) << 2) = (Index >> 2) - 3. % %% So Offset = ((Index >> 4) << 2) - 2 = (Index >> 2) - (3 + 2). % Tmp1 = hipe_rtl:mk_new_reg(), % Tmp2 = hipe_rtl:mk_new_reg(), % Shift = ?TAG_IMMED1_SIZE - 2, % OffAdj = (?TAG_IMMED1_SMALL bsr Shift) + ?TAG_PRIMARY_BOXED, % [hipe_rtl:mk_alu(Tmp1, Index, 'srl', hipe_rtl:mk_imm(Shift)), % hipe_rtl:mk_alu(Tmp2, Tmp1, 'sub', hipe_rtl:mk_imm(OffAdj)), % hipe_rtl:mk_load(Dst, Tuple, Tmp2)]. element(Dst, Index, Tuple, FailLab, {tuple, A}, IndexInfo) -> FailLabName = hipe_rtl:label_name(FailLab), FixnumOkLab = hipe_rtl:mk_new_label(), IndexOkLab = hipe_rtl:mk_new_label(), Ptr = hipe_rtl:mk_new_reg(), UIndex = hipe_rtl:mk_new_reg(), Arity = hipe_rtl:mk_imm(A), InvIndex = hipe_rtl:mk_new_reg(), Offset = hipe_rtl:mk_new_reg(), case IndexInfo of valid -> %% This is no branch, 1 load and 3 alus = 4 instr [hipe_rtl:mk_alu(UIndex, Index, 'sra',hipe_rtl:mk_imm(?TAG_IMMED1_SIZE)), hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)), hipe_rtl:mk_alu(Offset, UIndex, 'sll', hipe_rtl:mk_imm(2)), hipe_rtl:mk_load(Dst, Ptr, Offset)]; fixnums -> %% This is 1 branch, 1 load and 4 alus = 6 instr [hipe_rtl:mk_alu(UIndex, Index,'sra',hipe_rtl:mk_imm(?TAG_IMMED1_SIZE)), hipe_rtl:mk_alu(Ptr, Tuple, 'sub',hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED))| gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset, UIndex, FailLabName, IndexOkLab)]; _ -> %% This is 3 branches, 1 load and 5 alus = 9 instr [test_fixnum(Index, hipe_rtl:label_name(FixnumOkLab), FailLabName, 0.99), FixnumOkLab, hipe_rtl:mk_alu(UIndex, Index,'sra',hipe_rtl:mk_imm(?TAG_IMMED1_SIZE)), hipe_rtl:mk_alu(Ptr, Tuple, 'sub',hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED))| gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset, UIndex, FailLabName, IndexOkLab)] end; element(Dst, Index, Tuple, FailLab, tuple, IndexInfo) -> FailLabName = hipe_rtl:label_name(FailLab), FixnumOkLab = hipe_rtl:mk_new_label(), IndexOkLab = hipe_rtl:mk_new_label(), Ptr = hipe_rtl:mk_new_reg(), Header = hipe_rtl:mk_new_reg(), UIndex = hipe_rtl:mk_new_reg(), Arity = hipe_rtl:mk_new_reg(), InvIndex = hipe_rtl:mk_new_reg(), Offset = hipe_rtl:mk_new_reg(), case IndexInfo of fixnums -> %% This is 1 branch, 2 loads and 5 alus = 8 instr [hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)), hipe_rtl:mk_load(Header, Ptr, hipe_rtl:mk_imm(0)), hipe_rtl:mk_alu(UIndex, Index, 'sra',hipe_rtl:mk_imm(?TAG_IMMED1_SIZE)), hipe_rtl:mk_alu(Arity,Header,'srl',hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))| gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset, UIndex, FailLabName, IndexOkLab)]; Num when is_integer(Num) -> %% This is 1 branch, 1 load and 3 alus = 5 instr [hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED))| gen_element_tail(Dst, Ptr, InvIndex, hipe_rtl:mk_imm(Num), Offset, UIndex, FailLabName, IndexOkLab)]; _ -> %% This is 2 branches, 2 loads and 6 alus = 10 instr [test_fixnum(Index, hipe_rtl:label_name(FixnumOkLab), FailLabName, 0.99), FixnumOkLab, hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)), hipe_rtl:mk_load(Header, Ptr, hipe_rtl:mk_imm(0)), hipe_rtl:mk_alu(UIndex, Index, 'sra',hipe_rtl:mk_imm(?TAG_IMMED1_SIZE)), hipe_rtl:mk_alu(Arity,Header,'srl',hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))| gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset, UIndex, FailLabName, IndexOkLab)] end; element(Dst, Index, Tuple, FailLab, _TupleInfo, IndexInfo) -> FailLabName = hipe_rtl:label_name(FailLab), FixnumOkLab = hipe_rtl:mk_new_label(), BoxedOkLab = hipe_rtl:mk_new_label(), TupleOkLab = hipe_rtl:mk_new_label(), IndexOkLab = hipe_rtl:mk_new_label(), Ptr = hipe_rtl:mk_new_reg(), Header = hipe_rtl:mk_new_reg(), Tmp = hipe_rtl:mk_new_reg(), UIndex = hipe_rtl:mk_new_reg(), Arity = hipe_rtl:mk_new_reg(), InvIndex = hipe_rtl:mk_new_reg(), Offset = hipe_rtl:mk_new_reg(), case IndexInfo of fixnums -> %% This is 3 branches, 2 loads and 5 alus = 10 instr [test_is_boxed(Tuple, hipe_rtl:label_name(BoxedOkLab), FailLabName, 0.99), BoxedOkLab, hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)), hipe_rtl:mk_load(Header, Ptr, hipe_rtl:mk_imm(0)), hipe_rtl:mk_alub(Tmp, Header, 'and', hipe_rtl:mk_imm(?TAG_HEADER_MASK), 'eq', hipe_rtl:label_name(TupleOkLab), FailLabName, 0.99), TupleOkLab, hipe_rtl:mk_alu(UIndex, Index, 'sra',hipe_rtl:mk_imm(?TAG_IMMED1_SIZE)), hipe_rtl:mk_alu(Arity, Header, 'srl', hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))| gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset, UIndex, FailLabName, IndexOkLab)]; Num when is_integer(Num) -> %% This is 3 branches, 2 loads and 4 alus = 9 instr [test_is_boxed(Tuple, hipe_rtl:label_name(BoxedOkLab), FailLabName, 0.99), BoxedOkLab, hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)), hipe_rtl:mk_load(Header, Ptr, hipe_rtl:mk_imm(0)), hipe_rtl:mk_alub(Tmp, Header, 'and', hipe_rtl:mk_imm(?TAG_HEADER_MASK), 'eq', hipe_rtl:label_name(TupleOkLab), FailLabName, 0.99), TupleOkLab, hipe_rtl:mk_alu(Arity, Header, 'srl', hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))| gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset, hipe_rtl:mk_imm(Num), FailLabName, IndexOkLab)]; _ -> %% This is 4 branches, 2 loads, and 6 alus = 12 instr :( [test_fixnum(Index, hipe_rtl:label_name(FixnumOkLab), FailLabName, 0.99), FixnumOkLab, test_is_boxed(Tuple, hipe_rtl:label_name(BoxedOkLab), FailLabName, 0.99), BoxedOkLab, hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)), hipe_rtl:mk_load(Header, Ptr, hipe_rtl:mk_imm(0)), hipe_rtl:mk_alub(Tmp, Header, 'and', hipe_rtl:mk_imm(?TAG_HEADER_MASK), 'eq', hipe_rtl:label_name(TupleOkLab), FailLabName, 0.99), TupleOkLab, hipe_rtl:mk_alu(UIndex, Index, 'sra',hipe_rtl:mk_imm(?TAG_IMMED1_SIZE)), hipe_rtl:mk_alu(Arity, Header, 'srl', hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))| gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset, UIndex, FailLabName, IndexOkLab)] end. gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset, UIndex, FailLabName, IndexOkLab)-> %% now check that 1 <= UIndex <= Arity %% if UIndex < 1, then (Arity - UIndex) >= Arity %% if UIndex > Arity, then (Arity - UIndex) < 0, which is >=u Arity %% otherwise, 0 <= (Arity - UIndex) < Arity [hipe_rtl:mk_alu(InvIndex, Arity, 'sub', UIndex), hipe_rtl:mk_branch(InvIndex, 'geu', Arity, FailLabName, hipe_rtl:label_name(IndexOkLab), 0.01), IndexOkLab, hipe_rtl:mk_alu(Offset, UIndex, 'sll', hipe_rtl:mk_imm(2)), hipe_rtl:mk_load(Dst, Ptr, Offset)]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% unsafe_closure_element(Dst, Index, Closure) -> % Index is an immediate Offset = -(?TAG_PRIMARY_BOXED) %% Untag + ?EFT_ENV %% Field offset + (4 * (hipe_rtl:imm_value(Index)-1)), %% Index from 1 to N hence -1) hipe_rtl:mk_load(Dst, Closure, hipe_rtl:mk_imm(Offset)). mk_fun_header() -> hipe_rtl:mk_imm(?HEADER_FUN). tag_fun(Res, X) -> tag_boxed(Res, X). untag_fun(Res, X) -> hipe_rtl:mk_alu(Res, X, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)). if_fun_get_arity_and_address(ArityReg, AddressReg, FunP, BadFunLab, Pred) -> % EmuAddressPtrReg = hipe_rtl:mk_new_reg(), % FEPtrReg = hipe_rtl:mk_new_reg(), % ArityReg = hipe_rtl:mk_new_reg(), % NumFreeReg = hipe_rtl:mk_new_reg(), % RealArityReg = hipe_rtl:mk_new_reg(), TrueLab0 = hipe_rtl:mk_new_label(), % TrueLab1 = hipe_rtl:mk_new_label(), IsFunCode = test_fun(FunP, hipe_rtl:label_name(TrueLab0), BadFunLab, Pred), GetArityCode = [TrueLab0, %% Funp->arity contains the arity hipe_rtl:mk_load(ArityReg, FunP, hipe_rtl:mk_imm(-(?TAG_PRIMARY_BOXED)+ ?EFT_ARITY)), hipe_rtl:mk_load(AddressReg, FunP, hipe_rtl:mk_imm(-(?TAG_PRIMARY_BOXED)+ ?EFT_NATIVE_ADDRESS))], IsFunCode ++ GetArityCode. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Floating point stuff. % unsafe_untag_float(Dst, Src) -> %% The tag is 2. Use 2 as offset and we don't have to untag. [hipe_rtl:mk_fload(Dst, Src, hipe_rtl:mk_imm(2))]. unsafe_tag_float(Dst, Src, Options) -> {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(), Head = hipe_rtl:mk_imm(mk_header(2, ?TAG_HEADER_FLOAT)), Code = [GetHPInsn, hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0), Head), hipe_rtl:mk_fstore(HP, hipe_rtl:mk_imm(4), Src), tag_flonum(Dst, HP), hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(12)), PutHPInsn], case ?AddGC(Options) of true -> [hipe_rtl:mk_gctest(3)|Code]; false -> Code end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Binary stuff % finalize_bin(Dst, Base, Offset, TrueLblName) -> {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(), TmpOffset = hipe_rtl:mk_new_reg(), Tmp1 = hipe_rtl:mk_new_reg(), Tmp2 = hipe_rtl:mk_new_reg(), HeapLbl = hipe_rtl:mk_new_label(), REFCLbl = hipe_rtl:mk_new_label(), ProcBinHeader = hipe_rtl:mk_imm(mk_header(?PROC_BIN_BYTESIZE-1, ?TAG_HEADER_REFC_BIN)), [GetHPInsn, tag_boxed(Dst, HP), hipe_rtl:mk_alu(TmpOffset, Offset, sra, hipe_rtl:mk_imm(3)), hipe_rtl:mk_branch(TmpOffset, le, hipe_rtl:mk_imm(?MAX_HEAP_BIN_SIZE), hipe_rtl:label_name(HeapLbl), hipe_rtl:label_name(REFCLbl)), HeapLbl, hipe_rtl:mk_alu(Tmp1, HP, add, TmpOffset), hipe_rtl:mk_alu(Tmp2, Tmp1, add, hipe_rtl:mk_imm(11)), hipe_rtl:mk_alu(HP, Tmp2, 'and', hipe_rtl:mk_imm(16#fffffffc)), PutHPInsn, hipe_rtl:mk_goto(TrueLblName), REFCLbl, hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(?PROC_BIN_THING_WORD), ProcBinHeader), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(?PROC_BIN_BINSIZE), TmpOffset), heap_arch_spec(HP), hipe_rtl:mk_alu(Tmp2, Base, sub, hipe_rtl:mk_imm(?BINARY_ORIG_BYTES)), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(?PROC_BIN_VAL), Tmp2), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(?PROC_BIN_BYTES), Base), hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(?PROC_BIN_BYTESIZE*4)), PutHPInsn, hipe_rtl:mk_goto(TrueLblName)]. -ifdef(HEAP_ARCH_PRIVATE). heap_arch_spec(HP) -> Tmp1 = hipe_rtl:mk_new_reg(), [hipe_rtl_arch:pcb_load(Tmp1, ?P_OFF_HEAP_MSO), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(?PROC_BIN_NEXT), Tmp1), hipe_rtl_arch:pcb_store(?P_OFF_HEAP_MSO, HP)]. -else. heap_arch_spec(HP) -> Tmp1 = hipe_rtl:mk_new_reg(), MSO = hipe_rtl:mk_new_reg(), [hipe_rtl:mk_load_address(MSO, erts_global_mso, c_const), hipe_rtl:mk_load(Tmp1, MSO, ?OFF_HEAP_MSO), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(?PROC_BIN_NEXT), Tmp1), hipe_rtl:mk_store(MSO, ?OFF_HEAP_MSO, HP)]. -endif. get_base(Base, ByteSize) -> {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(), Header = hipe_rtl:mk_new_reg(), Tmp1 = hipe_rtl:mk_new_reg(), Tmp2 = hipe_rtl:mk_new_reg(), EvenWordSize = hipe_rtl:mk_new_reg(), [GetHPInsn, hipe_rtl:mk_alu(Tmp1, ByteSize, add, hipe_rtl:mk_imm(3)), hipe_rtl:mk_alu(EvenWordSize, Tmp1, sra, hipe_rtl:mk_imm(2)), hipe_rtl:mk_alu(Tmp2, EvenWordSize, add, hipe_rtl:mk_imm(1)), hipe_rtl:mk_alu(Base, HP, add, hipe_rtl:mk_imm(8)), mk_var_header(Header, Tmp2, ?TAG_HEADER_HEAP_BIN), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0), Header), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(4), ByteSize), PutHPInsn]. unsafe_mk_sub_binary(Dst, Size, Offs, Orig) -> {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(), Head = hipe_rtl:mk_imm(mk_header(2, ?TAG_HEADER_SUB_BIN)), [GetHPInsn, hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0), Head), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(4), Size), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(8), Offs), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(12), Orig), tag_boxed(Dst, HP), hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(16)), PutHPInsn]. unsafe_mk_float(Dst, FloatLo, FloatHi) -> {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(), Head = hipe_rtl:mk_imm(mk_header(2, ?TAG_HEADER_FLOAT)), [GetHPInsn, hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0), Head), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(4), FloatLo), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(8), FloatHi), tag_boxed(Dst, HP), hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(12)), PutHPInsn]. unsafe_load_float(Dst1, Dst2, Src) -> case get(hipe_target_arch) of x86 -> [hipe_rtl:mk_load(Dst1, Src, hipe_rtl:mk_imm(2)), hipe_rtl:mk_load(Dst2, Src, hipe_rtl:mk_imm(6))]; ultrasparc -> [hipe_rtl:mk_load(Dst2, Src, hipe_rtl:mk_imm(2)), hipe_rtl:mk_load(Dst1, Src, hipe_rtl:mk_imm(6))] end. unsafe_mk_big(Dst, Src, Signedness, ultrasparc) -> {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(), PosHead = hipe_rtl:mk_imm(mk_header(1, ?TAG_HEADER_POS_BIG)), NegHead = hipe_rtl:mk_imm(mk_header(1, ?TAG_HEADER_NEG_BIG)), PosLabel = hipe_rtl:mk_new_label(), NegLabel = hipe_rtl:mk_new_label(), JoinLabel = hipe_rtl:mk_new_label(), Tmp1 = hipe_rtl:mk_new_reg(), [GetHPInsn | case Signedness of unsigned -> [hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0), PosHead), hipe_rtl:mk_alu(Tmp1, Src, sll, hipe_rtl:mk_imm(16)), hipe_rtl:mk_alu(Src, Src, srl, hipe_rtl:mk_imm(16)), hipe_rtl:mk_alu(Src, Src, 'or', Tmp1), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(4), Src), tag_boxed(Dst, HP), hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(8)), PutHPInsn]; signed -> [hipe_rtl:mk_alub(Tmp1, Src, 'and', hipe_rtl:mk_imm(1 bsl 31), eq, hipe_rtl:label_name(PosLabel), hipe_rtl:label_name(NegLabel)), PosLabel, hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0), PosHead), hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLabel)), NegLabel, hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0), NegHead), JoinLabel, hipe_rtl:mk_alu(Tmp1, Src, sll, hipe_rtl:mk_imm(16)), hipe_rtl:mk_alu(Src, Src, srl, hipe_rtl:mk_imm(16)), hipe_rtl:mk_alu(Src, Src, 'or', Tmp1), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(4), Src), tag_boxed(Dst, HP), hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(8)), PutHPInsn] end]; unsafe_mk_big(Dst, Src, Signedness, x86) -> {GetHPInsn, HP, PutHPInsn} = hipe_rtl_arch:heap_pointer(), PosHead = hipe_rtl:mk_imm(mk_header(1, ?TAG_HEADER_POS_BIG)), NegHead = hipe_rtl:mk_imm(mk_header(1, ?TAG_HEADER_NEG_BIG)), PosLabel = hipe_rtl:mk_new_label(), NegLabel = hipe_rtl:mk_new_label(), JoinLabel = hipe_rtl:mk_new_label(), Tmp1 = hipe_rtl:mk_new_reg(), [GetHPInsn | case Signedness of unsigned -> [hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0), PosHead), hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(4), Src), tag_boxed(Dst, HP), hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(8)), PutHPInsn]; signed -> [hipe_rtl:mk_alub(Tmp1, Src, 'and', hipe_rtl:mk_imm(1 bsl 31), eq, hipe_rtl:label_name(PosLabel), hipe_rtl:label_name(NegLabel)), PosLabel, hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0), PosHead), hipe_rtl:mk_goto(hipe_rtl:label_name(JoinLabel)), NegLabel, hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(0), NegHead), JoinLabel, hipe_rtl:mk_store(HP, hipe_rtl:mk_imm(4), Src), tag_boxed(Dst, HP), hipe_rtl:mk_alu(HP, HP, add, hipe_rtl:mk_imm(8)), PutHPInsn] end]. test_subbinary(Binary, TrueLblName, FalseLblName) -> Tmp1 = hipe_rtl:mk_new_reg(), Tmp2 = hipe_rtl:mk_new_reg(), [hipe_rtl:mk_load(Tmp1, Binary, hipe_rtl:mk_imm(-2)), hipe_rtl:mk_alu(Tmp2, Tmp1, 'and', hipe_rtl:mk_imm(?TAG_HEADER_MASK)), hipe_rtl:mk_branch(Tmp2, eq, hipe_rtl:mk_imm(?TAG_HEADER_SUB_BIN), TrueLblName, FalseLblName)]. test_heap_binary(Binary, TrueLblName, FalseLblName) -> Tmp1 = hipe_rtl:mk_new_reg(), Tmp2 = hipe_rtl:mk_new_reg(), [hipe_rtl:mk_load(Tmp1, Binary, hipe_rtl:mk_imm(-2)), hipe_rtl:mk_alu(Tmp2, Tmp1, 'and', hipe_rtl:mk_imm(?TAG_HEADER_MASK)), hipe_rtl:mk_branch(Tmp2, eq, hipe_rtl:mk_imm(?TAG_HEADER_HEAP_BIN), TrueLblName, FalseLblName)]. mk_var_header(Header, Size, Tag) -> Tmp = hipe_rtl:mk_new_reg(), [hipe_rtl:mk_alu(Tmp, Size, sll, hipe_rtl:mk_imm(?HEADER_ARITY_OFFS)), hipe_rtl:mk_alu(Header, Tmp, 'add', hipe_rtl:mk_imm(Tag))]. -------------- next part -------------- /* * $Id: hipe_mkliterals.c,v 1.28 2003/07/10 12:53:12 pergu Exp $ */ #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #if HIPE /* hipe_mkliterals is needed even if HIPE is not enabled */ #include "sys.h" #include "erl_vm.h" #include "global.h" #include "erl_process.h" #include "error.h" #include "erl_bits.h" #include "erl_message.h" /* this sucks, but the loaders need data for all platforms */ #include "hipe_x86_asm.h" #undef P #undef HP #undef NSP #undef TEMP0 #undef TEMP1 #undef ARG0 #undef ARG1 #undef ARG2 #include "hipe_sparc_registers.h" #undef P #undef HP #undef TEMP0 #undef TEMP1 #undef ARG0 #undef ARG1 #undef ARG2 #include "erl_binary.h" #endif /* HIPE */ static const unsigned long CRCTABLE[256] = { 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L, 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L, 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L, 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL, 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L, 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L, 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL, 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L, 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL, 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L, 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L, 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L, 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L, 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL, 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L, 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L, 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L, 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L, 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL, 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL, 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L, 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L, 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L, 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL, 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L, 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L, 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L, 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L, 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL, 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL, 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L, 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL, 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L, 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL, 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL, 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L, 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L, 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL, 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L, 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL, }; static const struct literal { const char *name; unsigned long value; } literals[] = { #if HIPE /* Field offsets in a process struct */ { "P_HP", offsetof(struct process, htop) }, #ifdef SHARED_HEAP { "P_HP_LIMIT", offsetof(struct process, hend) }, { "OFF_HEAP_MSO", offsetof(struct erl_off_heap, mso) }, #else { "P_HP_LIMIT", offsetof(struct process, stop) }, { "P_OFF_HEAP_FUNS", offsetof(struct process, off_heap.funs) }, { "P_OFF_HEAP_MSO", offsetof(struct process, off_heap.mso) }, #endif { "P_ID", offsetof(struct process, id) }, { "P_FLAGS", offsetof(struct process, flags) }, { "P_FVALUE", offsetof(struct process, fvalue) }, { "P_FREASON", offsetof(struct process, freason) }, { "P_FCALLS", offsetof(struct process, fcalls) }, { "P_BEAM_IP", offsetof(struct process, i) }, { "P_ARITY", offsetof(struct process, arity) }, { "P_ARG0", offsetof(struct process, def_arg_reg[0]) }, { "P_ARG1", offsetof(struct process, def_arg_reg[1]) }, { "P_ARG2", offsetof(struct process, def_arg_reg[2]) }, { "P_ARG3", offsetof(struct process, def_arg_reg[3]) }, { "P_ARG4", offsetof(struct process, def_arg_reg[4]) }, #if defined(__sparc__) { "P_ARG5", offsetof(struct process, def_arg_reg[5]) }, { "P_ARG6", offsetof(struct process, def_arg_reg[6]) }, { "P_ARG7", offsetof(struct process, def_arg_reg[7]) }, { "P_ARG8", offsetof(struct process, def_arg_reg[8]) }, { "P_ARG9", offsetof(struct process, def_arg_reg[9]) }, { "P_ARG10", offsetof(struct process, def_arg_reg[10]) }, { "P_ARG11", offsetof(struct process, def_arg_reg[11]) }, { "P_ARG12", offsetof(struct process, def_arg_reg[12]) }, { "P_ARG13", offsetof(struct process, def_arg_reg[13]) }, { "P_ARG14", offsetof(struct process, def_arg_reg[14]) }, { "P_ARG15", offsetof(struct process, def_arg_reg[15]) }, #endif { "P_NSP", offsetof(struct process, hipe.nsp) }, { "P_NCALLEE", offsetof(struct process, hipe.ncallee) }, { "P_CLOSURE", offsetof(struct process, hipe.closure) }, #if defined(__sparc__) { "P_NSP_LIMIT", offsetof(struct process, hipe.nstend) }, { "P_NRA", offsetof(struct process, hipe.nra) }, { "P_CRA", offsetof(struct process, hipe.ncra) }, #elif defined(__i386__) { "P_NSP_LIMIT", offsetof(struct process, hipe.nstack) }, { "P_CSP", offsetof(struct process, hipe.ncsp) }, { "P_NARITY", offsetof(struct process, hipe.narity) }, #endif /* process flags bits */ { "F_TIMO", F_TIMO }, /* freason codes */ { "FREASON_THROWN", THROWN }, { "FREASON_USER_EXIT", USER_EXIT }, { "FREASON_USER_ERROR", USER_ERROR }, { "FREASON_USER_ERROR2", USER_ERROR2 }, { "FREASON_TRAP", TRAP }, { "FREASON_RESCHEDULE", RESCHEDULE }, /* special Erlang constants */ { "ERL_NIL", NIL }, { "THE_NON_VALUE", THE_NON_VALUE }, /* funs */ { "EFE_BUCKET", offsetof(struct erl_fun_entry, bucket) }, { "EFE_OLD_UNIQ", offsetof(struct erl_fun_entry, old_uniq) }, { "EFE_OLD_INDEX", offsetof(struct erl_fun_entry, old_index) }, { "EFE_ADDRESS", offsetof(struct erl_fun_entry, address) }, { "EFE_NATIVE_ADDRESS", offsetof(struct erl_fun_entry, native_address) }, { "EFE_MODULE", offsetof(struct erl_fun_entry, module) }, { "EFE_REFC", offsetof(struct erl_fun_entry, refc) }, { "EFT_THING", offsetof(struct erl_fun_thing, thing_word) }, #ifndef SHARED_HEAP { "EFT_NEXT", offsetof(struct erl_fun_thing, next) }, #endif { "EFT_CREATOR", offsetof(struct erl_fun_thing, creator) }, { "EFT_FE", offsetof(struct erl_fun_thing, fe) }, { "EFT_NATIVE_ADDRESS", offsetof(struct erl_fun_thing, native_address) }, { "EFT_ARITY", offsetof(struct erl_fun_thing, arity) }, { "EFT_NUM_FREE", offsetof(struct erl_fun_thing, num_free) }, { "EFT_ENV", offsetof(struct erl_fun_thing, env[0]) }, { "ERL_FUN_SIZE", ERL_FUN_SIZE }, /* bit syntax */ { "BSF_ALIGNED", BSF_ALIGNED}, { "BSF_LITTLE", BSF_LITTLE}, { "BSF_SIGNED", BSF_SIGNED}, { "BSF_EXACT", BSF_EXACT}, { "MB_ORIG", offsetof(struct erl_bin_match_buffer, orig) }, { "MB_BASE", offsetof(struct erl_bin_match_buffer, base) }, { "MB_OFFSET", offsetof(struct erl_bin_match_buffer, offset) }, { "MB_SIZE", offsetof(struct erl_bin_match_buffer, size) }, { "PROC_BIN_THING_WORD", offsetof(struct proc_bin, thing_word) }, { "PROC_BIN_BINSIZE", offsetof(struct proc_bin, size) }, { "PROC_BIN_NEXT", offsetof(struct proc_bin, next) }, { "PROC_BIN_VAL", offsetof(struct proc_bin, val) }, { "PROC_BIN_BYTES", offsetof(struct proc_bin, bytes) }, { "PROC_BIN_BYTESIZE", PROC_BIN_SIZE}, { "BINARY_ORIG_BYTES", offsetof(struct binary, orig_bytes) }, { "MAX_HEAP_BIN_SIZE", ERL_ONHEAP_BIN_LIMIT}, { "OVERHEAD_FACTOR", (BINARY_OVERHEAD_FACTOR*sizeof(Eterm))}, /* x86 */ { "X86_NR_ARG_REGS", X86_NR_ARG_REGS }, #if X86_HP_IN_ESI { "X86_HP_IN_ESI", 1 }, #endif #if X86_SIMULATE_NSP { "X86_SIMULATE_NSP", 1 }, #endif /* SPARC */ { "HIPE_SPARC_LEAF_WORDS", HIPE_SPARC_LEAF_WORDS }, { "SPARC_ARGS_IN_REGS", HIPE_SPARC_ARGS_IN_REGS}, { "SPARC_REG_P", P_NR}, { "SPARC_REG_NSP", NSP_NR}, { "SPARC_REG_NSP_LIMIT", NSP_LIMIT_NR}, { "SPARC_REG_HP", HP_NR}, { "SPARC_REG_HP_LIMIT", HP_LIMIT_NR}, { "SPARC_REG_FCALLS", FCALLS_NR}, { "SPARC_REG_RA", RA_NR}, { "SPARC_REG_TEMP0", TEMP0_NR}, { "SPARC_REG_TEMP1", TEMP1_NR}, { "SPARC_REG_TEMP2", TEMP2_NR}, { "SPARC_REG_TEMP3", TEMP3_NR}, { "SPARC_REG_ARG0", ARG0_NR}, { "SPARC_REG_ARG1", ARG1_NR}, { "SPARC_REG_ARG2", ARG2_NR}, { "SPARC_REG_ARG3", ARG3_NR}, { "SPARC_REG_ARG4", ARG4_NR}, { "SPARC_REG_ARG5", ARG5_NR}, { "SPARC_REG_ARG6", ARG6_NR}, { "SPARC_REG_ARG7", ARG7_NR}, { "SPARC_REG_ARG8", ARG8_NR}, { "SPARC_REG_ARG9", ARG9_NR}, { "SPARC_REG_ARG10", ARG10_NR}, { "SPARC_REG_ARG11", ARG11_NR}, { "SPARC_REG_ARG12", ARG12_NR}, { "SPARC_REG_ARG13", ARG13_NR}, { "SPARC_REG_ARG14", ARG14_NR}, { "SPARC_REG_ARG15", ARG15_NR}, #else /* !HIPE, fake minimum set to allow compiling the loaders */ { "SPARC_ARGS_IN_REGS", 0 }, { "P_BEAM_IP", 0 }, { "P_ARITY", 0 }, #endif /* HIPE */ #ifdef SHARED_HEAP { "HEAP_ARCH_SHARED", 1 }, #else { "HEAP_ARCH_PRIVATE", 1 }, #endif }; #define NLITERALS ((sizeof literals)/sizeof(literals[0])) /* * The algorithm for calculating the 32 bit CRC checksum is based upon * documentation and algorithms provided by Dr. Ross N. Williams in the * document "A Painless Guide to CRC Error Detection Algorithms." * This document may be downloaded from * ftp://ftp.rocksoft.com/cliens/rocksoft/papers/crc_v3.txt * as of 12/15/1998. Dr. Williams has placed this document and algorithms * in the public domain. */ static unsigned long crc_init(void) { return 0xFFFFFFFF; } static unsigned long crc_update(unsigned long crc_value, const void *buf, unsigned int length) { const unsigned char *tab; tab = (const unsigned char*)buf; for(; length > 0; --length) { unsigned char t = (crc_value >> 24) & 0xFF; crc_value = (crc_value << 8) | *tab++; crc_value ^= CRCTABLE[t]; } return crc_value; } static unsigned long literals_crc(void) { unsigned long crc_value; unsigned int i; crc_value = crc_init(); for(i = 0; i < NLITERALS; ++i) crc_value = crc_update(crc_value, &literals[i].value, sizeof(literals[i].value)); return crc_value & 0x07FFFFFF; } static void c_print1(FILE *fp, const struct literal *literal) { fprintf(fp, "#define %s %lu\n", literal->name, literal->value); } static void e_print1(FILE *fp, const struct literal *literal) { fprintf(fp, "-define(%s,%lu).\n", literal->name, literal->value); } static void printall(FILE *fp, void (*print1)(FILE*,const struct literal*)) { unsigned int i; for(i = 0; i < NLITERALS; ++i) (*print1)(fp, &literals[i]); } static int do_c(FILE *fp) { fprintf(fp, "/* File: hipe_literals.h, generated by hipe_mkliterals */\n"); fprintf(fp, "#ifndef __HIPE_LITERALS_H__\n"); fprintf(fp, "#define __HIPE_LITERALS_H__\n\n"); printall(fp, c_print1); fprintf(fp, "#define HIPE_SYSTEM_CRC %luL\n", literals_crc()); fprintf(fp, "\n#endif\n"); return 0; } static int do_e(FILE *fp) { fprintf(fp, "%% File: hipe_literals.hrl, generated by hipe_mkliterals\n\n"); printall(fp, e_print1); fprintf(fp, "-define(HIPE_SYSTEM_CRC,%lu).\n", literals_crc()); return 0; } int main(int argc, const char **argv) { if( argc > 0 ) { if( strcmp(argv[1], "-c") == 0 ) return do_c(stdout); if( strcmp(argv[1], "-e") == 0 ) return do_e(stdout); } fprintf(stderr, "usage: %s [-c | -e] > output-file\n", argv[0]); return 1; } From bry@REDACTED Tue Sep 16 11:25:16 2003 From: bry@REDACTED (bryan) Date: Tue, 16 Sep 2003 11:25:16 +0200 Subject: callto protocol? Message-ID: <002901c37c34$70e957b0$2001a8c0@bryans> Hi, I'm wondering if anyone has been doing anything with the callto: protocol in erlang. -------------- next part -------------- An HTML attachment was scrubbed... URL: From hal@REDACTED Tue Sep 16 13:31:01 2003 From: hal@REDACTED (Hal Snyder) Date: Tue, 16 Sep 2003 06:31:01 -0500 Subject: [Erlyaws-list] Performance testing In-Reply-To: <3F6691B2.5030702@cwru.edu> (Leon Smith's message of "Mon, 15 Sep 2003 23:29:38 -0500") References: <3F667D2D.4080306@texoma.net> <3F6691B2.5030702@cwru.edu> Message-ID: <87fzixrmve.fsf@ghidra.vail> Leon Smith writes: > Change your uri to: > > --uri=/hellowww.html > > Now, I am not extremely well versed on the URI standard, but my > understanding is that your uri isn't technically legit. Browsers > always send an absolute uri to a webserver. This is something we > should handle more gracefully so as not to pollute error logs. We are > working on improving URL handling. We are aware of this issue but I > was under the impression this had been fixed. :-) > > So this does bring up a question for the list... how should Yaws > respond to such a uri? Assuming my understanding of the standard is > correct, I'm inclined to not pollute the standard and return a 403. My .02 on this obscure case: My reading of rfc2396 is that it's a relative URI with no base (5.1.4) so result is application dependent. Normally a web server doesn't see these because it's impossible to specify a server and a relative path in a URI. Web browsers tend to take the reasonable approach of fetching hellowww.html from cwd on local filesystem. The --server argument on httperf gets the relative URI to the web server in this case. Result is application dependent (so we can do whatever we want), but you could argue in favor of compatibility with other servers on this point and assume a base of /. From hal@REDACTED Tue Sep 16 14:46:54 2003 From: hal@REDACTED (Hal Snyder) Date: Tue, 16 Sep 2003 07:46:54 -0500 Subject: [Erlyaws-list] Performance testing In-Reply-To: <87fzixrmve.fsf@ghidra.vail> (Hal Snyder's message of "Tue, 16 Sep 2003 06:31:01 -0500") References: <3F667D2D.4080306@texoma.net> <3F6691B2.5030702@cwru.edu> <87fzixrmve.fsf@ghidra.vail> Message-ID: <87ad94sxxd.fsf@ghidra.vail> Hal Snyder writes: > My .02 on this obscure case: .. sorry, wrong list From richardc@REDACTED Tue Sep 16 15:02:47 2003 From: richardc@REDACTED (Richard Carlsson) Date: Tue, 16 Sep 2003 15:02:47 +0200 (MET DST) Subject: Broadcast In-Reply-To: <20030910093537.0f81e414.cpressey@catseye.mine.nu> References: <200309100219.h8A2J79V362642@atlas.otago.ac.nz> <20030910093537.0f81e414.cpressey@catseye.mine.nu> Message-ID: Hi everybody! I have a little poll for you about message broadcast (multicast) protocols, that I hope you will respond to if you think it relates to you in any way: 1. Do you use broadcasts (multicasts) in any application today? If so: a) What form? (reliable? total/causal order? "safe"? etc.) b) What broadcast implementation? c) What application are you using it in? d) Do you have problems with scalability or other things? 2. Are you explicitly not using broadcasts in some application because of some known problem with existing broadcast implementations? If so, what are those problems, and what methods are you using instead? 3. Are there problems which you think you could solve more easily if you had access to a better reliable, scalable broadcast? If so, what number of processes do you think you would need to be able to scale to? 4. Do you have a program that would make a good benchmark for testing message broadcasts? The reason I'm asking is that I am considering letting a student do a master's thesis on the subject of probabilistic broadcast with an implementation in Erlang. We need to know more about possible practical applications and opportunities for benchmarking. /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ "Having users is like optimization: the wise course is to delay it." -- Paul Graham From crav@REDACTED Tue Sep 16 12:00:35 2003 From: crav@REDACTED (=?iso-8859-1?Q?Carlos_Rodr=EDguez_Alcal=E1_Villagra?=) Date: Tue, 16 Sep 2003 12:00:35 +0200 Subject: MEGACO commnads structures 2 Message-ID: <001001c37c39$6011df70$6600a8c0@carlos> Hi there, I have seen that the structures used for the MEGACO commands are defined inside the archive "megaco.hrl"(and megaco_message_v1.hrl) . But, I could not find all the structures related to the MEGACO commands. The ones I found are SubtractRequest, NotifyRequest and ServiceChangeRequest. Where are the others? I guess that probably they are all there but I couldn't find it because (maybe) they have a different name.(exampple AmmRequest may be == Addcommand???) Is there any documentation about these structures and the usage of the commands? Any help is welcome, Farewell, Carlos R. A. Another aswer:Is there any documentation about megaco_session ?? i'cant install -------------- next part -------------- An HTML attachment was scrubbed... URL: From crav@REDACTED Tue Sep 16 12:01:45 2003 From: crav@REDACTED (=?iso-8859-1?Q?Carlos_Rodr=EDguez_Alcal=E1_Villagra?=) Date: Tue, 16 Sep 2003 12:01:45 +0200 Subject: megaco_session Message-ID: <002101c37c39$891f5d20$6600a8c0@carlos> Is there any documentation about megaco_session ?? -------------- next part -------------- An HTML attachment was scrubbed... URL: From erlang@REDACTED Tue Sep 16 17:33:01 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Tue, 16 Sep 2003 16:33:01 +0100 Subject: MEGACO commnads structures 2 In-Reply-To: <001001c37c39$6011df70$6600a8c0@carlos> References: <001001c37c39$6011df70$6600a8c0@carlos> Message-ID: <3F672D2D.4090308@manderp.freeserve.co.uk> Hi Carlos, I can see that you're going through the same process of discovery as I did. You need to get hold of the ABNF or ASN.1 grammar of Megaco, because a lot of answers will come directly from there. For example, ou need to use atoms to distinguish various 'CommandRequest' from each other. An add request is represented as: make_add_command(Params,TermId) -> #'CommandRequest'{ command = {addReq,make_ammReq(Params,TermId)}}. ^^^^^^ note the addReq atom, that's what you need to supply, and you will find all the other names in the Megaco grammar specification. Sorry, but I must go now, I'll fill in more details tomorrow. Bon courage! Pete. Carlos Rodr?guez Alcal? Villagra wrote: > > Hi there, > I have seen that the structures used for the MEGACO commands are defined > inside the archive "megaco.hrl"(and megaco_message_v1.hrl) . But, I > could not find all the structures related to the MEGACO commands. The > ones I found are SubtractRequest, NotifyRequest and ServiceChangeRequest. > Where are the others? I guess that probably they are all there but I > couldn't find it because (maybe) they have a different name.(exampple > AmmRequest may be == Addcommand???) > Is there any documentation about these structures and the usage of the > commands? > Any help is welcome, > > Farewell, > Carlos R. A. > Another aswer: Is there any documentation about megaco_session ?? i'cant > install From klacke@REDACTED Tue Sep 16 22:25:45 2003 From: klacke@REDACTED (Klacke) Date: Tue, 16 Sep 2003 22:25:45 +0200 Subject: linked in driver on win32/cygwin/gcc Message-ID: <20030916202545.GA28985@bluetail.com> Title says it all: Anybody knows how ? /klacke -- Claes Wikstrom -- Caps lock is nowhere and Alteon WebSystems -- everything is under control http://www.bluetail.com/~klacke cellphone: +46 70 2097763 From michael@REDACTED Tue Sep 16 23:18:11 2003 From: michael@REDACTED (Michael Hobbs) Date: Tue, 16 Sep 2003 16:18:11 -0500 (CDT) Subject: linked in driver on win32/cygwin/gcc In-Reply-To: <20030916202545.GA28985@bluetail.com> References: <20030916202545.GA28985@bluetail.com> Message-ID: <2111.66.41.245.83.1063747091.squirrel@mail.hobbshouse.org> Klacke said: > Title says it all: Anybody knows how ? Can't use erl_interface for now. Other than that, I use: gcc -shared -o $(DRIVER).dll -I "$(ERL_TOP)/usr/include" $(DRIVER).c From enewhuis@REDACTED Wed Sep 17 00:01:02 2003 From: enewhuis@REDACTED (Eric Newhuis) Date: Tue, 16 Sep 2003 17:01:02 -0500 Subject: Debugging a Release Message-ID: <3F67881E.900@futuresource.com> Is it possible to use the Erlang graphical debugger to debug a release? I am confused by the order of initialization. A boot script is involved. But I want to set breakpoints in my supervised gen_server init code. Actually I am not sure what question to ask yet. But does this ring familiar with anyone? Can anyone point me toward some docs or previous threads on this subject? Sincerely, Eric Newhuis From rvg@REDACTED Wed Sep 17 09:10:17 2003 From: rvg@REDACTED (Rudolph van Graan) Date: Wed, 17 Sep 2003 09:10:17 +0200 Subject: Debugging a Release In-Reply-To: <3F67881E.900@futuresource.com> Message-ID: Hi Eric, I am not sure if this will help you, but I'll try nevertheless. Usually, if something goes wrong during initialization, you'll only get the supervisor to show "**shutdown**" without any reasonable error messages. It is then very difficult to troubleshoot. After digging through the source, I found that the supervisor does actually give out detailed info. Our solution has been to write a very simple event handler: -module(errortrace). -export([init/1,handle_event/2]). init(Args) -> {ok,[]}. handle_event(What,State) -> io:format("Event: ~w\n",[What]), {ok,State}. that you then install into the error_logger: error_logger:add_report_handler(errortrace). It will now dump a lot of extra information onto stdio. The reports we were interested in were the "supervisor" ones that you can easily filter out. Usually, you'll be able to see a clear error in there somewhere. Does anyone know of a better way of seeing the error reports during supervisor initialization? Regards, Rudolph On Wednesday, Sep 17, 2003, at 00:01 Africa/Johannesburg, Eric Newhuis wrote: > Is it possible to use the Erlang graphical debugger to debug a > release? I am confused by the order of initialization. A boot script > is involved. But I want to set breakpoints in my supervised > gen_server init code. > > Actually I am not sure what question to ask yet. But does this ring > familiar with anyone? Can anyone point me toward some docs or > previous threads on this subject? > > Sincerely, > Eric Newhuis > > From hakan@REDACTED Wed Sep 17 09:09:37 2003 From: hakan@REDACTED (Hakan Mattsson) Date: Wed, 17 Sep 2003 09:09:37 +0200 (MEST) Subject: megaco_session In-Reply-To: <002101c37c39$891f5d20$6600a8c0@carlos> Message-ID: On Tue, 16 Sep 2003, Carlos Rodr?guez Alcal? Villagra wrote: > Is there any documentation about megaco_session ?? The only documentation is the megaco_session/doc/README file. It can be found in the latest tar-ball: http://www.erlang.org/project/megaco/download.html#megaco_session-0.5 /H?kan --- H?kan Mattsson Ericsson High Availability Software, DBMS Internals http://www.erlang.org/~hakan/ From micael.karlberg@REDACTED Tue Sep 16 17:52:13 2003 From: micael.karlberg@REDACTED (Micael Karlberg) Date: Tue, 16 Sep 2003 17:52:13 +0200 Subject: megaco_session In-Reply-To: <002101c37c39$891f5d20$6600a8c0@carlos> References: <002101c37c39$891f5d20$6600a8c0@carlos> Message-ID: <16231.12717.427147.531854@gargle.gargle.HOWL> Hi, The megaco_session app is not an offially supported app, so the only documentaion you will find is the examples and documentaion included in the tar-balls on the megaco download page. Regards, /BMK Carlos Rodr?guez Alcal? Villagra writes: > Is there any documentation about megaco_session ?? > > > > > > > >
Is there any documentation about megaco_session ??
From serge@REDACTED Wed Sep 17 15:18:00 2003 From: serge@REDACTED (Serge Aleynikov) Date: Wed, 17 Sep 2003 09:18:00 -0400 Subject: SNMP: error report In-Reply-To: References: Message-ID: <3F685F08.4040405@hq.idt.net> There's a little bug in the snmp-3.4 release: when compiled with -define(snmp_debug, ok) snmp_mib.erl doesn't compile due to the following errors: --------------------------- code_change({down, _Vsn}, State, downgrade_to_pre_3_4) -> ?debug("code_change(down) -> entry with~n" " Vsn: ~p~n" " Extra: ~p", - [Vsn,downgrade_to_pre_3_4]), + [_Vsn,downgrade_to_pre_3_4]), NData = snmp_mib_data:code_change({down,pre_3_4},State#state.data), put(te_override, State#state.teo), put(me_override, State#state.meo), {ok, {state, NData}}; %% upgrade code_change(_Vsn, State, upgrade_from_pre_3_4) -> ?debug("code_change(up) -> entry with~n" " Vsn: ~p~n" " Extra: ~p", - [Vsn,upgrade_from_pre_3_4]), + [_Vsn,upgrade_from_pre_3_4]), --------------------------- Also, the sample community.conf file generated by the configuration utility has the following example setting commented: %% {1, "public", "initial", "", ""}. %% {2, "secret", "secret_name", "", "tag"}. %% {3, "bridge1", "initial", "bridge1", ""}. This should be changed to: %% {"1", "public", "initial", "", ""}. %% {"2", "secret", "secret_name", "", "tag"}. %% {"3", "bridge1", "initial", "bridge1", ""}. as the first parameter is expected to be a string. Regards, Serge From mlogan@REDACTED Wed Sep 17 16:29:06 2003 From: mlogan@REDACTED (Martin J. Logan) Date: 17 Sep 2003 09:29:06 -0500 Subject: Style Message-ID: <1063808945.2708.1034.camel@dhcp-lom-194-186.futuresource.com> I the programming rules documentation on erlang.org it states "Comments within Erlang code shall start with one percent character (%). If a line only contains a comment, it shall be indented as Erlang code. This kind of comment shall be placed above the statement it refers to. If the comment can be placed at the same line as the statement, this is preferred." I use the erlang mode for emacs to edit my code and must wonder why it forces comments with a single percent sign to the far right of my screen. This is not consistent with the programming rules. Should this be changed? Martin From cpressey@REDACTED Wed Sep 17 18:27:59 2003 From: cpressey@REDACTED (Chris Pressey) Date: Wed, 17 Sep 2003 09:27:59 -0700 Subject: filelib:fold_files/5 In-Reply-To: <20030916160015.4c2d3614.cpressey@catseye.mine.nu> References: <20030916160015.4c2d3614.cpressey@catseye.mine.nu> Message-ID: <20030917092759.4d0863a7.cpressey@catseye.mine.nu> Sorry to reply to my own message, but I've given this some thought, and at this point I think it's more question than bug report so I'm forwarding it to erlang-questions. To recap, filelib:fold_files/5... - is a great idea - is documented - does not work at all :( - is written to only visit plain files, never directories - requires a global regexp - requires a global recursion flag I think the way to maximize the utility of this function is to... - make it visit both files and directories and pass an IsDir flag - make it not require a global regexp (make the fun check, itself) - let the fun return a local recursion flag (fine-grained recursion) This way, you can (say) use different regexps on plain files and directories, and you can skip entire subtrees that you do not want to scan. This is much more powerful. My proposal is a completely rewritten function, fold_files/3. fold_files/5 can easily be rewritten as a wrapper around fold_files/3. I've included them both below, for your perusal. %% @spec fold_files(dir(), fun(), term()) -> term() %% @doc Folds the function Fun(F, IsDir, Acc) -> {Recurse, Acc1} over %% all files F in Dir that match the regular expression RegExp. %% If Recurse is true all sub-directories of F are processed. %% (This function is a modified version of that from filelib.erl) fold_files(Dir, Fun, Acc) -> case file:list_dir(Dir) of {ok, Files} -> fold_files0(Files, Dir, Fun, Acc); {error, _} -> Acc end. fold_files0([File | Tail], Dir, Fun, Acc) -> FullName = filename:join([Dir, File]), IsDir = filelib:is_dir(FullName), {Recurse, NewAcc} = Fun(FullName, IsDir, Acc), fold_files0(FullName, Tail, Dir, Fun, IsDir, Recurse, NewAcc); fold_files0([], Dir, Fun, Acc) -> Acc. fold_files0(FullName, Tail, Dir, Fun, true, true, Acc) -> NewAcc = fold_files(FullName, Fun, Acc), fold_files0(Tail, Dir, Fun, NewAcc); fold_files0(FullName, Tail, Dir, Fun, _, _, Acc) -> fold_files0(Tail, Dir, Fun, Acc). %% @spec fold_files(dir(), regexp(), bool(), fun(), term()) -> term() %% Wrapper for the original fold_files/5 behaviour. fold_files(Dir, RegExp, Recursive, Fun, InitialAcc) -> {ok, CompiledRegExp} = regexp:parse(RegExp), Wrapper = fun (FullName, false, Acc) -> NewAcc = case regexp:match(FullName, CompiledRegExp) of {match, _, _} -> Fun(FullName, Acc); _ -> Acc end, {Recursive, NewAcc}; (_, true, Acc) -> {Recursive, Acc} end, fold_files(Dir, Wrapper, InitialAcc). On Tue, 16 Sep 2003 16:00:15 -0700 Chris Pressey wrote: > Hi, > > No offense to Mr. Gustavsson, but filelib:fold_files/5 looks like it > was written while he was asleep :) > > Attached is a patch which makes it (at least) work. But I think it > would be good to consider a change to its definition first. > > With the present behaviour, the callback never sees directory entries > themselves. So, for example, empty directories are never detected. I > think the behaviour would be more useful if it called the fun for both > plain files and directories. The callback could also accept a flag, > like fun(Filename, IsDir, Acc), so that it doesn't have to do the test > itself (since fold_files/5 already does it anyway.) > > What do you think? > > Other than that one issue, I like the filelib module a lot! Keep up > the good work. > > -Chris > From tony@REDACTED Wed Sep 17 19:46:40 2003 From: tony@REDACTED (Tony Rogvall) Date: 17 Sep 2003 19:46:40 +0200 Subject: Bug in regs() Message-ID: <1063820800.4778.16.camel@bit.hemma.se> Try this at home: 1> Port = open_port({spawn, "cat"}, []). #Port<0.28> 2> flush(). ok 3> register(cat, Port). true 4> regs(). ** Registered procs on node nonode@REDACTED ** Name Pid Initial Call Reds Msgs application_controlle <0.5.0> application_controller:in 1509 0 =ERROR REPORT==== 17-Sep-2003::19:42:57 === Error in process <0.24.0> with exit value: {badarg,[{erlang,process_info,[#Port<0.28>]},{c,pinfo,1},{c,display_name_info,2},{lists,foreach,2},{erl_eval,do_apply,5},{shell,eval_loop,2}]} ** exited: {badarg,[{erlang,process_info,[#Port<0.28>]}, {c,pinfo,1}, {c,display_name_info,2}, {lists,foreach,2}, {erl_eval,do_apply,5}, {shell,eval_loop,2}]} ** ------------ Should be simple to fix. BTW registered ports is a nice feature, (meaning do not remove the possiblility to register ports as a fix ;-) BTW2 a command pi() could be nice to have (port info list) -- Tony Rogvall -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 307 bytes Desc: This is a digitally signed message part URL: From luke@REDACTED Thu Sep 18 04:07:39 2003 From: luke@REDACTED (Luke Gorrie) Date: 18 Sep 2003 04:07:39 +0200 Subject: Style In-Reply-To: <1063808945.2708.1034.camel@dhcp-lom-194-186.futuresource.com> References: <1063808945.2708.1034.camel@dhcp-lom-194-186.futuresource.com> Message-ID: "Martin J. Logan" writes: > I the programming rules documentation on erlang.org it states > > "Comments within Erlang code shall start with one percent character (%). > If a line only contains a comment, it shall be indented as Erlang code. > This kind of comment shall be placed above the statement it refers to. > If the comment can be placed at the same line as the statement, this is > preferred." > > I use the erlang mode for emacs to edit my code and must wonder why it > forces comments with a single percent sign to the far right of my > screen. This is not consistent with the programming rules. Should this > be changed? The stated rules should be updated IMO. %% starts a whole-line comment, and % starts an inline comment. As in: %% comment about the following function foo() -> %% comment about the following line stuff(). % inline comment about this line That's how pretty much all the Erlang code in the world is written as far as I can see. (Most importantly the Erlang/OTP code itself). Note that the Emacs command M-; can be used to create aligned inline comments. The variable `comment-column' says where to align them. On the topic of programming style rules, there is an extremely good tutorial for Common Lisp called the "Tutorial on Good Lisp Programming Style" by Peter Norvig and Kent Pitman. Most of it applies equally to Erlang. Maybe useful source material for people teaching Erlang programming? URL is http://www.norvig.com/luv-slides.ps I have one page from it pinned up next to my computer. It is a reminder of commonly useful higher order functions, including the ones that you don't use every day. It could be paraphrased for Erlang's 'lists' module thus: Control Abstraction: Most algorithms can be characterised as: * Searching: member/2, any/2, keysearch/3 * Sorting: sort/1, sort/2, keysort/2 * Filtering: filter/2, dropwhile/2, takewhile/2, list comprehensions * Mapping: map/2, mapfold[lr]/3 * Combining: fold[lr]/3, flatmap/2, list comprehensions These higher-order functions abstract common control patterns. Code that uses them is: * Concise * Self-documenting * Easy to understand * Usually efficient Introducing your own higher-order functions is an important part of program design. (Very Robert Virding :-)) Cheers, Luke From cpressey@REDACTED Thu Sep 18 04:37:04 2003 From: cpressey@REDACTED (Chris Pressey) Date: Wed, 17 Sep 2003 19:37:04 -0700 Subject: erlc (R9C) hangs when last line is missing EOF Message-ID: <20030917193704.146f0c51.cpressey@catseye.mine.nu> Try this: -module(blah). %%% BEGIN blah %%% -export([foo/0]). foo() -> bar. %%% END of blah %%% ^ do not include an EOL here. # erlc foo.erl <> This happens for me both on FreeBSD-4.9 PRERELEASE and Windows 98. (Also, I can't seem to gracefully kill erlc on Windows 98 when this happens - Ctrl-C gives me the menu, but the 'a' option doesn't work.) This only seems to happen when the last line is a comment AND is missing an EOL. -Chris From erlang@REDACTED Thu Sep 18 07:46:59 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Thu, 18 Sep 2003 06:46:59 +0100 Subject: erlc (R9C) hangs when last line is missing EOF In-Reply-To: <20030917193704.146f0c51.cpressey@catseye.mine.nu> References: <20030917193704.146f0c51.cpressey@catseye.mine.nu> Message-ID: <3F6946D3.9060505@manderp.freeserve.co.uk> I've seen this on SuSE 8.2 linux too. There's an easy work-around (-: Pete. Chris Pressey wrote: > Try this: > > > -module(blah). > %%% BEGIN blah %%% > -export([foo/0]). > foo() -> bar. > %%% END of blah %%% > ^ do not include an EOL here. > > > # erlc foo.erl > <> > > This happens for me both on FreeBSD-4.9 PRERELEASE and Windows 98. > (Also, I can't seem to gracefully kill erlc on Windows 98 when this > happens - Ctrl-C gives me the menu, but the 'a' option doesn't work.) > > This only seems to happen when the last line is a comment AND is missing > an EOL. > > -Chris > > From erlang@REDACTED Thu Sep 18 09:51:05 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Thu, 18 Sep 2003 08:51:05 +0100 Subject: Interview with Stroustrup Message-ID: <3F6963E9.9070400@manderp.freeserve.co.uk> Hi Gurus, I'm only posting this out of malice (-: It's curious to read that Bjarn is, from an Erlang point of view at least, trying to reinvent the wheel wrt distributed computing. Having pretty much dropped C++ in favour of Erlang due to the vast simplification of code for most of my work, I find this mildly amusing. Can anyone with code-credibility steer Bjarn toward Erlang? He may appreciate a working example. Pete. http://www.linuxjournal.com/article.php?sid=7099&mode=thread&order=0&thold=0 Quote: "LJ:If it's not a secret, what do you research at your job? "BS: [...] I wanted to write a small program than needed to run with parts being on several computers. Conventionally, I'd have to write that program so the communication methods were explicit in the program. For example, if I used CORBA, my code would contain CORBA calls and I'd need to write IDL for the types I wanted to communicate between the parts of my program. If, on the other hand, I wanted the communication to use TCP/IP directly, my code would be full of TCP/IP library calls. Instead, I wrote a program where the communication between the parts were represented by ordinary C++ member function calls. If the object to be called was local, I directly called members of class X; if not, I called the same members of class proxy. Using a library with facilities for C++ program transformation, I then automatically converted the calls of proxy into message sent across a TCP/IP connection or, alternatively, to CORBA calls. [...] "LJ: What languages do you think are serious competitors to C++? "BS: That depend on the application. Sometime C++ is the best choice; at other times there are reasons to prefer a language such as Fortran, Java, C# or Python. And yet other times, one could use a more experimental language just to learn something new. There are many languages that are good for what they are designed for, and it is a mistake to rely solely on one language. On the other hand, competition is often based on marketing and perceptions rather than facts, and I'm not going to comment on that." From richardc@REDACTED Thu Sep 18 11:34:16 2003 From: richardc@REDACTED (Richard Carlsson) Date: Thu, 18 Sep 2003 11:34:16 +0200 (MET DST) Subject: Interview with Stroustrup In-Reply-To: <3F6963E9.9070400@manderp.freeserve.co.uk> References: <3F6963E9.9070400@manderp.freeserve.co.uk> Message-ID: On Thu, 18 Sep 2003, Peter-Henry Mander wrote: > It's curious to read that Bjarn is, from an Erlang point of view at > least, trying to reinvent the wheel wrt distributed computing. > > Having pretty much dropped C++ in favour of Erlang due to the vast > simplification of code for most of my work, I find this mildly amusing. Well, it's a terrible interview for sure, but that particular part juat sounds like he is implementing the Java RMI thing in C++. I don't think this kind of guy would even appreciate a laguage like Erlang - he'd probably feel that it's like cheating somehow. /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ "Having users is like optimization: the wise course is to delay it." -- Paul Graham From kenneth@REDACTED Thu Sep 18 11:37:15 2003 From: kenneth@REDACTED (Kenneth Lundin) Date: Thu, 18 Sep 2003 11:37:15 +0200 Subject: Enhanced type guard syntax] Message-ID: <3F697CCB.6000603@erix.ericsson.se> Below follows a suggestion regarding enhanced syntax for writing type guards in function clauses and in other match expressions. I post this to see if you in the Erlang community have some (positive or negative) opinions regarding this and I hope I get a lot of feedback. Enhanced type guard syntax --------------------------------------- The situation to day is that it is quite cumbersome to write type guards for a function and that it is unfair that some type constraints can be expressed directly in the argument list (list, tuple,Binary) while other type constraints must be expressed in the guard (integer,atom,float,pid,port,fun) where the argument names have to be repeated again. The idea is originally from Mats Cronqvist AXD. Examples as it is today: ------------------------ % The constraint that A and B must be integers % must be expressed in the guard notation with the arguments repeated % foo(A, B) when integer(A), integer(B) -> A * B. % The constraint that it must be a list (with at least one element) % can be expressed directly in the argumentlist % bar([H|T]) -> H. Proposed solution ------------------ Examples with new suggested syntax: ----------------------------------- % The type constraint expressed directly in the argument list % Shorter to write % Exactly the same semantics as the foo example above % The compiler has potential of handling these type constraints more efficiently than today % and this syntax makes the different type of guards more visible % foo(A/integer, B/integer) -> A * B. {X/float, Y/float} = graph:coordinates(), The rationale behind this suggestion is that we already have the Variable/type syntax in the matchexpressions for binaries (example: <> = <<2,"AB","CD">>) It is unfair that some types can be matched without guard syntax while others can't. It will result in a more compact and intuitive way of writing that will encourage writing type constraints which will catch errors as early and efficient as possible. The allowed type specifiers should be all the type test BIFs named is_XXX/1 but without the "is_" prefix. Alternative syntax ------------------- Of course some other special character can be used to distinguish the type constraint from other tokens and one idea could be to make this as an extension to the '_' (don't care) notation which then indicates don't care the value but it should be of a certain type. foo(A = $integer, B = $integer) -> A*B. foo(A = _$integer, B = _$integer) -> Advantages with this solution could be that it does only introduce the new variants of typed don't care. /Regards Kenneth Lundin Product Manager of Erlang/OTP From carsten@REDACTED Thu Sep 18 11:52:46 2003 From: carsten@REDACTED (Carsten Schultz) Date: Thu, 18 Sep 2003 11:52:46 +0200 Subject: Interview with Stroustrup In-Reply-To: <3F6963E9.9070400@manderp.freeserve.co.uk> References: <3F6963E9.9070400@manderp.freeserve.co.uk> Message-ID: <20030918095246.GA23127@penne.localnet> This max be off-topic, but anyway... On Thu, Sep 18, 2003 at 08:51:05AM +0100, Peter-Henry Mander wrote: > Hi Gurus, > > I'm only posting this out of malice (-: > > It's curious to read that Bjarn is, from an Erlang point of view at > least, trying to reinvent the wheel wrt distributed computing. [...] > BS: [...] Instead, I wrote a program where the communication between > the parts were represented by ordinary C++ member function calls. If > the object to be called was local, I directly called members of > class X; if not, I called the same members of class proxy. I do not remember the terminology or the details, but remote objects via proxys were available in Objective C on NextStep. I do not know, if they have survived... There may be something original in the mentioned work, though. It is hard to tell from the brief description. Greetings, Carsten -- Carsten Schultz (2:40, 33:47), FB Mathematik, FU Berlin http://carsten.fu-mathe-team.de/ PGP/GPG key on the pgp.net key servers, fingerprint on my home page. -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 240 bytes Desc: not available URL: From vlad_dumitrescu@REDACTED Thu Sep 18 12:07:27 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Thu, 18 Sep 2003 12:07:27 +0200 Subject: Enhanced type guard syntax] References: <3F697CCB.6000603@erix.ericsson.se> Message-ID: Hi, > Below follows a suggestion regarding enhanced syntax for > writing type guards in function clauses and in other match expressions. I think it is a great proposal, one of those I wish I thought of first :-) I think the first way looks better, and is also easier to understand. > foo(A/integer, B/integer) -> > A * B. This is new: > {X/float, Y/float} = graph:coordinates(), The alternative today is much hairier to write, so it's a welcomed addition for me. Will a type mismatch be treated just as any other pattern mismatch? I suppose there won't be any automatic type coercions (between float and integer), would they? Maybe this could be extended to somehow be able to pack the size() guard in a similar way (a la binary syntax)? > The allowed type specifiers should be all the > type test BIFs named is_XXX/1 but without the "is_" prefix. I'd like to suggest allowing a "string" type declaration too, making it a equivalent to "list". Maybe sometime there will be a string type... regards, Vlad From luke@REDACTED Thu Sep 18 12:09:53 2003 From: luke@REDACTED (Luke Gorrie) Date: 18 Sep 2003 12:09:53 +0200 Subject: Interview with Stroustrup In-Reply-To: References: <3F6963E9.9070400@manderp.freeserve.co.uk> Message-ID: Richard Carlsson writes: > On Thu, 18 Sep 2003, Peter-Henry Mander wrote: > > > It's curious to read that Bjarn is, from an Erlang point of view at > > least, trying to reinvent the wheel wrt distributed computing. > > > > Having pretty much dropped C++ in favour of Erlang due to the vast > > simplification of code for most of my work, I find this mildly amusing. > > Well, it's a terrible interview for sure, but that particular part juat > sounds like he is implementing the Java RMI thing in C++. I don't think > this kind of guy would even appreciate a laguage like Erlang - he'd > probably feel that it's like cheating somehow. But cheating is quite popular in distributed-OO circles. Here's an excerpt from a very popular book called "The Pragmatic Programmer": We once worked on a project that required that a certain body of Java code run both locally on a server machine and remotely on a client machine. The alternatives for distributing classes this way were RMI and CORBA. If a class were made remotely accessible using RMI, every call to a remote method in that class could potentially throw an exception, which means that a naive implementation would require us to handle the exception whenever our remote classes were used. Using RMI here is clearly not orthogonal: code calling our remote classes should not have to be aware of their locations. The alternative - using CORBA - did not impose that restriction: we could write code that was unaware of our classes' locations. Of course, in both cases it _will_ throw an exception when communications are down. The CORBA binding just makes it easier to ignore this by not declaring to the compiler that a communications error can happen and must be handled. So with CORBA you can be Pragmatic and write simple code that works just fine provided nothing fails :-) Of course, making the compiler check that you have acknowledged the exceptional cases is far from solving the problems of distributed computing, but the RMI guys did understand the issues very well: http://citeseer.nj.nec.com/waldo94note.html Cheers, Luke From Bengt.Kleberg@REDACTED Thu Sep 18 12:59:53 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Thu, 18 Sep 2003 12:59:53 +0200 Subject: Enhanced type guard syntax] In-Reply-To: <3F697CCB.6000603@erix.ericsson.se> References: <3F697CCB.6000603@erix.ericsson.se> Message-ID: <3F699029.1030001@ericsson.com> Kenneth Lundin wrote: ...deleted > Examples as it is today: > ------------------------ > > % The constraint that A and B must be integers > % must be expressed in the guard notation with the arguments repeated > % > foo(A, B) when integer(A), integer(B) -> > A * B. to help beginners i find it to be a good idea to use ''modern'' erlang as much as possible in examples, etc. this example should (imho) be: foo(A, B) when is_integer(A) and is_integer(B) -> A*B. ...deleted > Proposed solution > ------------------ > > Examples with new suggested syntax: > ----------------------------------- > > % The type constraint expressed directly in the argument list > % Shorter to write > % Exactly the same semantics as the foo example above > % The compiler has potential of handling these type constraints more > efficiently than today > % and this syntax makes the different type of guards more visible > % > foo(A/integer, B/integer) -> > A * B. > > > {X/float, Y/float} = graph:coordinates(), this seems to be the best way. > Alternative syntax > ------------------- > > Of course some other special character can be used to distinguish the > type constraint from other tokens and one idea could be to make this as > an extension to the '_' (don't care) notation which then indicates don't > care the value but it should be of a certain type. > > foo(A = $integer, B = $integer) -> > A*B. > > foo(A = _$integer, B = _$integer) -> > > Advantages with this solution could be that it does only introduce the > new variants of typed don't care. > surely this alternative syntax is confusing? when i see 'A = _$integer' i take it to mean that the value is of interest, and the type might be integer, but i do not care. foo( _A/integer, _B/integer ) -> is ''the best'' way to express 'do not care about value, but type must be correct'. bengt, who really wants type checking, please. From Bengt.Kleberg@REDACTED Thu Sep 18 13:17:54 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Thu, 18 Sep 2003 13:17:54 +0200 Subject: Interview with Stroustrup In-Reply-To: References: <3F6963E9.9070400@manderp.freeserve.co.uk> Message-ID: <3F699462.9030104@ericsson.com> Richard Carlsson wrote: > ...deleted > sounds like he is implementing the Java RMI thing in C++. I don't think > this kind of guy would even appreciate a laguage like Erlang - he'd > probably feel that it's like cheating somehow. > about 10 years ago i read a book by stroustrup. it was about the design of c++. it seemed full of cheats. one page would claim that the design descision was due to clearity of source expression beeing much more important than compiler speed. a few pages later claimed that backwards compatibility (to c) was more important than clearity of source. and a little later again it was compiler speed that was more important than backwards compatibility. that book made me unhappy. but that could be me. bengt From enewhuis@REDACTED Thu Sep 18 13:22:05 2003 From: enewhuis@REDACTED (Eric Newhuis) Date: Thu, 18 Sep 2003 06:22:05 -0500 Subject: Enhanced type guard syntax] In-Reply-To: <3F697CCB.6000603@erix.ericsson.se> References: <3F697CCB.6000603@erix.ericsson.se> Message-ID: <3F69955D.2000806@futuresource.com> This is a wonderful suggestion. I would welcome it. Furthermore I would also welcome compile-time checking in cases where it is practical. Such a small thing could be a stepping stone to some ultimate type system. > foo(A/integer, B/integer) -> > A * B. What is the runtime expense of performing such checks? The technique I employ is liberal use of unit tests so I can avoid type checking at runtime and gain a slight performance advantage. But perhaps this is an illusion? What is the real expense? Would this lead the way to a user-defined type system some day, one that even supports recursive type definitions? -type (blammo, [atom() | blammo()]). foo (A/blammo, B/blammo) -> blammize (A, B). Maybe I've been hanging around ObjectiveCAML too much. M. Logan probably thinks I'm crazy. ;-) -e From enewhuis@REDACTED Thu Sep 18 13:25:04 2003 From: enewhuis@REDACTED (Eric Newhuis) Date: Thu, 18 Sep 2003 06:25:04 -0500 Subject: Compile-Time Module/Function Verification Message-ID: <3F699610.5000409@futuresource.com> I wonder if it is possible to verify literal module and function references at compile time. I've been bitten quite a few times by spelling errors that lead to runtime errors. Luckily for me I use a lot of unit tests and can usually find these quickly. I suppose the answer today is to use the xref tool? -e From Bengt.Kleberg@REDACTED Thu Sep 18 13:36:29 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Thu, 18 Sep 2003 13:36:29 +0200 Subject: Compile-Time Module/Function Verification In-Reply-To: <3F699610.5000409@futuresource.com> References: <3F699610.5000409@futuresource.com> Message-ID: <3F6998BD.9020606@ericsson.com> Eric Newhuis wrote: > I wonder if it is possible to verify literal module and function > references at compile time. not now. > I've been bitten quite a few times by spelling errors that lead to > runtime errors. errare humanum est :-) > Luckily for me I use a lot of unit tests and can > usually find these quickly. sounds like skill, not luck. > I suppose the answer today is to use the > xref tool? yes. bengt From fredrik.linder@REDACTED Thu Sep 18 13:57:03 2003 From: fredrik.linder@REDACTED (Fredrik Linder) Date: Thu, 18 Sep 2003 13:57:03 +0200 Subject: Enhanced type guard syntax] In-Reply-To: <3F697CCB.6000603@erix.ericsson.se> Message-ID: > foo(A/integer, B/integer) -> > A * B. > > {X/float, Y/float} = graph:coordinates(), This looks really really nice! Again, I'd like to ask for user-defined guards, as it would really enhance ... erlang(?). /Fredrik From thomas.arts@REDACTED Thu Sep 18 14:14:35 2003 From: thomas.arts@REDACTED (Thomas Arts) Date: Thu, 18 Sep 2003 14:14:35 +0200 Subject: Enhanced type guard syntax] References: <3F697CCB.6000603@erix.ericsson.se> <3F69955D.2000806@futuresource.com> Message-ID: <001701c37dde$6d782d30$a22d1081@ituniv398> > What is the runtime expense of performing such checks? There is a little overhead when you have the basic datastructures. It gets wors for datastructures that become complicated, like a record with fields that contain records, which are lists etc. I wrote a dynamic type checker in 1998, worked fine. Problem is that the source code is changed and people tend not to like that :0). Attached is the main module of that project. I saw that it was made for the old jam binaries, instead of for the beam. Got really out of sync and you need to adopt it to R9 if you want to use it. Guess it's two days work for a good programmer. > Would this lead the way to a user-defined type system some day, one that > even supports recursive type definitions? > > -type (blammo, [atom() | blammo()]). > foo (A/blammo, B/blammo) -> > blammize (A, B). That's indeed what we are missing. However, there was a philosophy that all guards should be executable in constant time. In case of recursively defined user types, this does not hold any longer. /Thomas --- Dr Thomas Arts Program Manager Software Engineering and Management IT-university in Gothenburg Box 8718, 402 75 Gothenburg, Sweden http://www.ituniv.se/ Tel +46 31 772 6031 Fax +46 31 772 4899 -------------- next part -------------- A non-text attachment was scrubbed... Name: dtc_typefun.erl Type: application/octet-stream Size: 10229 bytes Desc: not available URL: From Bengt.Kleberg@REDACTED Thu Sep 18 14:30:04 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Thu, 18 Sep 2003 14:30:04 +0200 Subject: Enhanced type guard syntax] In-Reply-To: <001701c37dde$6d782d30$a22d1081@ituniv398> References: <3F697CCB.6000603@erix.ericsson.se> <3F69955D.2000806@futuresource.com> <001701c37dde$6d782d30$a22d1081@ituniv398> Message-ID: <3F69A54C.3080006@ericsson.com> Thomas Arts wrote: ...deleted > I wrote a dynamic type checker in 1998, worked fine. Problem is that the have you looked a the new type checker, as presented at the erlang workshop '03, in uppsala? would you care to comment upon similarities/differences/etc? bengt From joe@REDACTED Thu Sep 18 15:16:48 2003 From: joe@REDACTED (Joe Armstrong) Date: Thu, 18 Sep 2003 15:16:48 +0200 (CEST) Subject: Enhanced type guard syntax] In-Reply-To: <3F69955D.2000806@futuresource.com> Message-ID: On Thu, 18 Sep 2003, Eric Newhuis wrote: > This is a wonderful suggestion. I would welcome it. Furthermore I > would also welcome compile-time checking in cases where it is > practical. Such a small thing could be a stepping stone to some > ultimate type system. > > > foo(A/integer, B/integer) -> > > A * B. > > What is the runtime expense of performing such checks? It depends upon the set of patterns. If we have a polymorphic function like this: foo(A/integer, B/...) -> foo(A/integer, B/...) foo(true, ...) -> foo(bar, ...) -> Then any half decent pattern matching compiler could generate pattern matching code like this.... switchOnTag Arg0 { case integer: ... case atom: ... } But with no type information the pattern matching code might be far worse. My general feeling is that "the more you tell the compiler about the program the better" As a programmer you shouldn't think about how to write patterns, or guards for efficiency - let the pattern matching compiler do that. If you *do* make assumptions about this your assumptions may well turn out wrong in the next version of the system, and you optimisations might turn into pessimisations /Joe > > The technique I employ is liberal use of unit tests so I can avoid type > checking at runtime and gain a slight performance advantage. But > perhaps this is an illusion? What is the real expense? > > Would this lead the way to a user-defined type system some day, one that > even supports recursive type definitions? > > -type (blammo, [atom() | blammo()]). > foo (A/blammo, B/blammo) -> > blammize (A, B). > > Maybe I've been hanging around ObjectiveCAML too much. M. Logan > probably thinks I'm crazy. ;-) > > -e > > From joe@REDACTED Thu Sep 18 15:51:50 2003 From: joe@REDACTED (Joe Armstrong) Date: Thu, 18 Sep 2003 15:51:50 +0200 (CEST) Subject: Enhanced type guard syntax] In-Reply-To: <3F697CCB.6000603@erix.ericsson.se> Message-ID: > % The type constraint expressed directly in the argument list > % Shorter to write > % Exactly the same semantics as the foo example above > % The compiler has potential of handling these type constraints more > efficiently than today > % and this syntax makes the different type of guards more visible > % > foo(A/integer, B/integer) -> > A * B. > > > {X/float, Y/float} = graph:coordinates(), > > The rationale behind this suggestion is that we already have the > Variable/type syntax in the matchexpressions for binaries (example: > <> = <<2,"AB","CD">>) > It is unfair that some types can be matched without guard syntax while > others can't. > It will result in a more compact and intuitive way of writing that will > encourage writing type constraints which will catch errors as early and > efficient as possible. The allowed type specifiers should be all the > type test BIFs named is_XXX/1 but without the "is_" prefix. > Adding guards like this violates one of my favorite design meta-principles: " If you add something to a language you have to chuck something away " What are we going to chuck away? Well not "when ->" ... Since you can't say foo(X, Y) when X == 2*Y -> in the new syntax So you keep "when" - now there are TWO ways of saying things foo(A/integer, B/integer) or foo(A, B) when is_integer(A), is_integer(B) -> and people will write: foo(A/integer, B) when is_integer(B) -> ... etc. And the integer guard test is proposed to be called integer in one place and is_integer somewhere else Adding the new syntax without removing something will *increase* the complexity of the language. Since the change adds no semantic power I am against it. Now if you want to add something add "proper" structs and throw away records and include files with record headers. Meta comment - Erlang is becoming more and more complicated. Can we please start checking stuff away to make the language simple. To hasten this process I'd like to add a new declaration to the the language. All modules should start. -needsErlangVersion(N). Where N is the language version. Then when you add/remove language features you will know what version of the compiler handles what feature. There is nothing worse than writing some code using the "latest" version of the system and posting the code to somebody using an earlier version just to be told that "the program doesn't work". Suppose: 1) I write a program using version (say) 5 of the system, which has some feature not present in system version 4. 2) I post the program to the net 3) Somebody running version 4 tries running my program When they do 3 they should get a *helpful* message - You need version 5 of the system - do you want me to live-update your system: [y] They type y - and the system gets the latest version of the system and installs it for them :-) What I do not want to happen if for either the compilation of execution to fail and for them to send me a bug report - this has happened *many* times. Then once we have got the versioning in we can start chucking things away. Get rid of spawn(Mod,Func,Args) ... and all the stupid "having to export spawned functions" these are hangbacks to the days before funs. You only need spawn(fun() -> ...) Keeping the system backwards compatible builds up *enormous* problems in the future - by all means add things - but throw away the old junk at the same time. If you number the versions with needsErlangVersion(N) you will even be able to semi-automate the transition from one version to another. Without knowing the language version this is difficult /Cheers Joe From joe@REDACTED Thu Sep 18 15:57:55 2003 From: joe@REDACTED (Joe Armstrong) Date: Thu, 18 Sep 2003 15:57:55 +0200 (CEST) Subject: Enhanced type guard syntax] In-Reply-To: Message-ID: On Thu, 18 Sep 2003, Fredrik Linder wrote: > > foo(A/integer, B/integer) -> > > A * B. > > > > {X/float, Y/float} = graph:coordinates(), > > This looks really really nice! > > Again, I'd like to ask for user-defined guards, as it would really enhance > ... erlang(?). > No - guards are extensions of patterns. They have to be simple, so that a pattern matching compiler can do a good job on them. If we had user defined guards somebody will write: foo(X) when bar(X), a == b -> ... Where bar(X) a user defined guard. Now what happens if somebody writes: bar(P) -> P ! a, true. But the guard fails (ie a==b) fails, did the message get sent????? Cheers /Joe From vlad_dumitrescu@REDACTED Thu Sep 18 16:16:12 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Thu, 18 Sep 2003 16:16:12 +0200 Subject: Enhanced type guard syntax] References: Message-ID: Joe wrote: > Adding guards like this violates one of my favorite design > meta-principles: " If you add something to a language you have to chuck something > away " > > What are we going to chuck away? Well not "when ->" ... Since you can't say > foo(X, Y) when X == 2*Y -> > in the new syntax > So you keep "when" - now there are TWO ways of saying things > foo(A/integer, B/integer) > or > foo(A, B) when is_integer(A), is_integer(B) -> > and people will write: > foo(A/integer, B) when is_integer(B) -> > ... > etc. Why not throw away the "when is_integer()" guards? Let type be only be specified using the new syntax, and let other kind of guards be specified as before. It seems to me it should work. What do you think? Of course, this would break backwards compatibility. Since I'm not at Ericsson (anymore) I can happily propose to write a tool for automated conversion of code to the new format. :-) regards, Vlad From fredrik.linder@REDACTED Thu Sep 18 16:13:11 2003 From: fredrik.linder@REDACTED (Fredrik Linder) Date: Thu, 18 Sep 2003 16:13:11 +0200 Subject: Use-defined guard (was: RE: Enhanced type guard syntax]) In-Reply-To: Message-ID: > -----Original Message----- > From: Joe Armstrong [mailto:joe@REDACTED] > Sent: den 18 september 2003 15:58 > To: Fredrik Linder > Cc: erlang-questions@REDACTED > Subject: RE: Enhanced type guard syntax] > > > On Thu, 18 Sep 2003, Fredrik Linder wrote: > > > > foo(A/integer, B/integer) -> > > > A * B. > > > > > > {X/float, Y/float} = graph:coordinates(), > > > > This looks really really nice! > > > > Again, I'd like to ask for user-defined guards, as it would > really enhance > > ... erlang(?). > > > > No - guards are extensions of patterns. They have to be simple, > so that a pattern matching compiler can do a good job on them. > > If we had user defined guards somebody will write: > > foo(X) when bar(X), a == b -> > ... > > Where bar(X) a user defined guard. > > Now what happens if somebody writes: > > bar(P) -> P ! a, true. > > But the guard fails (ie a==b) fails, did the message get sent????? > > Cheers > > /Joe Yes, you are right in the sense that code that utilize distribution should not be allowed as guard functions, neither should those utilizing "permanent" storage, such as accessing ets tables and files. And I do realize the potential overwelming task of keeping track of these things. However, by allowing only a limited set of operations in guard-declared functions (such as only allowing then to call other guard-functions) could be the fine line that increases usability while still preserving the consistency of the program. The usage I am targeting is to have user-defined guards as inspectors/selectors on ADTs. Cheers /Fredrik From fredrik.linder@REDACTED Thu Sep 18 16:34:53 2003 From: fredrik.linder@REDACTED (Fredrik Linder) Date: Thu, 18 Sep 2003 16:34:53 +0200 Subject: Enhanced type guard syntax] In-Reply-To: Message-ID: > > foo(A/integer, B/integer) -> > > A * B. > > > > {X/float, Y/float} = graph:coordinates(), > > This looks really really nice! Actually, I've changed my mind... <:-) A little too fast there, I was. I think it reduces readability, so I vote against. :-) I like the separation the when-clause provides. Cheers /Fredrik From Bengt.Kleberg@REDACTED Thu Sep 18 16:46:55 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Thu, 18 Sep 2003 16:46:55 +0200 Subject: Enhanced type guard syntax] In-Reply-To: References: Message-ID: <3F69C55F.4000308@ericsson.com> Joe Armstrong wrote: ...deleted > Adding guards like this violates one of my favorite design > meta-principles: > > " If you add something to a language you have to chuck something > away " > although i am very much in favour of this meta-principle (i got very strong reactions when suggesting a removal before (as in: not at) the scheme strawman workshop (ICFP '98)), it does not apply in this particular case. this is not adding something, instead it is extending an already existing feature to be more orthogonal. it should make erlang easier to learn. Var/binary is no longer a special case, but just another example of Var/builtin_type. imho. on the other hand, having both foo(A, B) when integer(A), integer(B) -> and foo(A, B) when is_integer(A) and is_integer(B) -> is a very strong violation of the meta-principle. it should be dealt with asap. bengt From cpressey@REDACTED Thu Sep 18 17:09:21 2003 From: cpressey@REDACTED (Chris Pressey) Date: Thu, 18 Sep 2003 08:09:21 -0700 Subject: Enhanced type guard syntax] In-Reply-To: References: Message-ID: <20030918080921.3ebe542e.cpressey@catseye.mine.nu> On Thu, 18 Sep 2003 16:16:12 +0200 "Vlad Dumitrescu" wrote: > Joe wrote: > > Adding guards like this violates one of my favorite > > design > > meta-principles: " If you add something to a language you have > > to chuck > something > > away " > > > > What are we going to chuck away? Well not "when ->" ... Since > > you can't > say > > foo(X, Y) when X == 2*Y -> > > in the new syntax > > So you keep "when" - now there are TWO ways of saying things > > foo(A/integer, B/integer) > > or > > foo(A, B) when is_integer(A), is_integer(B) -> > > and people will write: > > foo(A/integer, B) when is_integer(B) -> > > ... > > etc. > > Why not throw away the "when is_integer()" guards? Let type be only be > specified using the new syntax, and let other kind of guards be > specified as before. It seems to me it should work. What do you think? I think you CAN throw "when" completely away IF you take this new syntax proposal to its logical extreme. foo(X, Y) when X == 2*Y becomes foo(X == 2 * Y) This could also handle the other cases currently handled by "when" in a much more readable fashion, viz: foo(X > 3, Y > 3) foo(1 < X < 10, is_integer(Y)) foo(X * Y > 100, X < Y) As you can maybe see, the rules change - no longer is it an argument list in the same way. The "," symbol takes on the meaning of "and", and the order that variables are mentioned establishes their bindings (so all the above examples would bind the first argument to X and the second to Y, even though sometimes X is mentioned more than once, sometimes there is no "," at all, etc.) But this would completely obviate all need for "when" clauses, AFAICS. What you would probably have to throw away would be easy constant-matching - you can't have a function head like foo(100, 200) -> anymore, because it doesn't "mean" anything; you have to either say foo(X == 100, Y == 200) or write a REALLY clever (probably detrimentally so) compiler. > Of course, this would break backwards compatibility. Throwing stuff out tends to do that... :) -Chris From ulf.wiger@REDACTED Thu Sep 18 17:12:38 2003 From: ulf.wiger@REDACTED (=?iso-8859-1?Q?Ulf_Wiger_=28=C4L2/EAB=29?=) Date: Thu, 18 Sep 2003 17:12:38 +0200 Subject: Enhanced type guard syntax] Message-ID: <76E5F712842F5F49A35738622BAA0F4F9EA728@ESEALNT442.al.sw.ericsson.se> On Sept 18 2003, Joe Armstrong wrote: > > Adding guards like this violates one of my favorite design >meta-principles: > > " If you add something to a language you have to chuck something >away " > > What are we going to chuck away? > > Well not "when ->" ... > > Since you can't say > > foo(X, Y) when X == 2*Y -> > > in the new syntax > > > Adding the new syntax without removing something will *increase* the >complexity of the language. Since the change adds no semantic power >I am against it. In principle, I agree. However, one big problem with the 'when... ->' syntax is that it's exceedingly ugly (well, at least exceedingly cumbersome.) The following code snippet from wings_deform.erl: twist_fun(y, {Cx,_,Cz}) -> fun(U, Min, {X0,Y,Z0}) when float(U), float(Min), float(X0), float(Y), float(Z0) -> Angle = U*(Y-Min), Cos = math:cos(Angle), Sin = math:sin(Angle), X = X0 - Cx, Z = Z0 - Cz, {X*Cos+Z*Sin+Cx,Y,Z*Cos-X*Sin+Cz} end; would be possible to write as: twist_fun(y, {Cx,_,Cz}) -> fun(U/float, Min/float, {X0/float, Y/float, Z0/float}) -> Angle = U*(Y-Min), Cos = math:cos(Angle), Sin = math:sin(Angle), X = X0 - Cx, Z = Z0 - Cz {X*Cos+Z*Sin+Cx,Y,Z*Cos-X*Sin+Cz} end; which I personally think is a significant face lift. Note for example that the complete function head in the second version is shorter than the guard declaration alone in the first version. That, and the first version forces the reader to jump back and forth in order to match the guards with the arguments. In this particular code (I believe), type guards are important from a performance perspective, since floating point operations are performed more efficiently if the compiler can _know_ that the input parameters are really floats. In general, type guards should be used more because they add safety and clarity. Unfortunately, with today's guard syntax, they are unnecessarily clumsy, and can actually serve to obfuscate the code rather than clarifying it. Also, it's consistent with the bit syntax, so the X/Type syntax has already been added to the language. For these reasons, I support the proposal. /Uffe From jonathan@REDACTED Thu Sep 18 17:36:24 2003 From: jonathan@REDACTED (Jonathan Coupe) Date: Thu, 18 Sep 2003 16:36:24 +0100 Subject: Interview with Stroustrup References: <3F6963E9.9070400@manderp.freeserve.co.uk> Message-ID: <001501c37dfa$b3854ee0$0100a8c0@mimbi> Luke Gorrie wrote: > But cheating is quite popular in distributed-OO circles. Here's an > excerpt from a very popular book called "The Pragmatic Programmer": > > We once worked on a project that required that a certain body of > Java code run both locally on a server machine and remotely on a > client machine. The alternatives for distributing classes this way > were RMI and CORBA. If a class were made remotely accessible using > RMI, every call to a remote method in that class could potentially > throw an exception, which means that a naive implementation would > require us to handle the exception whenever our remote classes were > used. Using RMI here is clearly not orthogonal: code calling our > remote classes should not have to be aware of their locations. The > alternative - using CORBA - did not impose that restriction: we > could write code that was unaware of our classes' locations. > > Of course, in both cases it _will_ throw an exception when > communications are down. The CORBA binding just makes it easier to > ignore this by not declaring to the compiler that a communications > error can happen and must be handled. So with CORBA you can be > Pragmatic and write simple code that works just fine provided nothing > fails :-) A friend travelled from the UK to Mexico recently for a genetic engineering conference. The hotel refused all her credit cards, so the manager had to be woken in the middle of the night to authorize some sort of sepcial arrangement. The next day she found that the same thing had happened to all the other Europeans - my bet is that someone, somewhere had written some very "pragmatic" code. - Jonathan From cpressey@REDACTED Thu Sep 18 19:18:05 2003 From: cpressey@REDACTED (Chris Pressey) Date: Thu, 18 Sep 2003 10:18:05 -0700 Subject: erlc (R9C) hangs when last line is is a comment missing EOL In-Reply-To: <3F6946D3.9060505@manderp.freeserve.co.uk> References: <20030917193704.146f0c51.cpressey@catseye.mine.nu> <3F6946D3.9060505@manderp.freeserve.co.uk> Message-ID: <20030918101805.39512802.cpressey@catseye.mine.nu> On Thu, 18 Sep 2003 06:46:59 +0100 Peter-Henry Mander wrote: > I've seen this on SuSE 8.2 linux too. There's an easy work-around (-: How very pragmatic of you to suggest that :) There are similar errors on these types of files with file:consult/1, file:eval/1, and erl_scan:string/1. I think I located the problem: erl_scan:scan_comment/6 doesn't have a clause for when the first argument is just 'eof'. I added one that calls done(Eof, [], Toks, Pos, eos), but it only has limited success (erl_scan:string/1 no longer crashes, but the other still do.) -Chris > Chris Pressey wrote: > > Try this: > > > > > > -module(blah). > > %%% BEGIN blah %%% > > -export([foo/0]). > > foo() -> bar. > > %%% END of blah %%% > > ^ do not include an EOL here. > > > > > > # erlc foo.erl > > <> > > > > This happens for me both on FreeBSD-4.9 PRERELEASE and Windows 98. > > (Also, I can't seem to gracefully kill erlc on Windows 98 when this > > happens - Ctrl-C gives me the menu, but the 'a' option doesn't > > work.) > > > > This only seems to happen when the last line is a comment AND is > > missing an EOL. > > > > -Chris > > > > > > From erlang@REDACTED Thu Sep 18 19:46:26 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Thu, 18 Sep 2003 18:46:26 +0100 Subject: erlc (R9C) hangs when last line is is a comment missing EOL In-Reply-To: <20030918101805.39512802.cpressey@catseye.mine.nu> References: <20030917193704.146f0c51.cpressey@catseye.mine.nu> <3F6946D3.9060505@manderp.freeserve.co.uk> <20030918101805.39512802.cpressey@catseye.mine.nu> Message-ID: <3F69EF72.1010402@manderp.freeserve.co.uk> Chris Pressey wrote: > On Thu, 18 Sep 2003 06:46:59 +0100 > Peter-Henry Mander wrote: > >>I've seen this on SuSE 8.2 linux too. There's an easy work-around (-: > > How very pragmatic of you to suggest that :) How very magnaminous of you to say so (: Sorry chris, please excuse my flippancy. I made a note of this on the list before, but it sank without trace, probably because there _is_ a trivial work-around and so it's not considered a problem. > There are similar errors on these types of files with file:consult/1, > file:eval/1, and erl_scan:string/1. Since you revealed more quirks beneath the hood, maybe it'll get fixed. Pete. From jamesh@REDACTED Thu Sep 18 20:36:52 2003 From: jamesh@REDACTED (James Hague) Date: Thu, 18 Sep 2003 13:36:52 -0500 Subject: erlc (R9C) hangs when last line is is a comment missing EOL Message-ID: >I think I located the problem: erl_scan:scan_comment/6 >doesn't have a clause for when the first argument is >just 'eof'. I added one that calls done(Eof, [], Toks, >Pos, eos), but it only has limited success >(erl_scan:string/1 no longer crashes, but the other >still do.) I would think this is a good argument for using a lexer-generator, like leex, instead of writing the Erlang lexer by hand. Of course, leex has never been an officially supported tool--why not? From valentin@REDACTED Thu Sep 18 20:45:29 2003 From: valentin@REDACTED (Valentin) Date: Thu, 18 Sep 2003 20:45:29 +0200 Subject: Enhanced type guard syntax] References: Message-ID: <004101c37e15$08ef7670$55ea1ec4@moneymaker> Sometimes it might be useful to be able to write: isOne( X ) when X == 1; X == "one" -> true; isOne( X ) -> false. Why would I ever want to (re)write it like this: isOne( X/integer ) -> case X of 1 -> true; _ -> false end; isOne( X/string ) -> case X of "one" -> true; _ -> false end. Most of the languages are either STRONGLY or weakly typed. Erlang can be both and more -- it can match patterns that can be specified/grouped through their semantics, not only syntax. For example, when we say ONE, we can write it as "1" or "one" -- it wouldn't change the meaning, right? Valentin. From vlad_dumitrescu@REDACTED Thu Sep 18 21:13:47 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Thu, 18 Sep 2003 21:13:47 +0200 Subject: Enhanced type guard syntax] References: <004101c37e15$08ef7670$55ea1ec4@moneymaker> Message-ID: Hi, > isOne( X ) when X == 1; X == "one" -> true; > isOne( X ) -> false. Why not isOne(1) -> true; isOne("one") ->true; % or maybe even % isOne("one")->isOne(1); isOne(_) ->false. ? Looks simpler to me ;-) > Most of the languages are either STRONGLY or weakly typed. > Erlang can be both and more -- it can match patterns that can > be specified/grouped through their semantics, not only syntax. > For example, when we say ONE, we can write it as "1" or > "one" -- it wouldn't change the meaning, right? In your example, the guards X==1 and X=="one" are not typing guards, but matching ones. Thus according to the proposal, they would remain valid. regards, Vlad From vlad_dumitrescu@REDACTED Thu Sep 18 21:23:48 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Thu, 18 Sep 2003 21:23:48 +0200 Subject: list handling functions Message-ID: Hi, Maybe tomorrow I will be ashamed to have asked a question whose answer is obvious, but here it goes: Are there any ways to simply express a 'map' (or similar) function that iterates over several lists at once? I use something like map2(Fun, A, B) -> map2(Fun, A, B, []). map2(Fun, [], _, Res) -> lists:reverse(Res); map2(Fun, _, [], Res) -> lists:reverse(Res); map2(Fun, [Ha|Ta],[Hb|Tb],Res)-> map2(Fun, Ta, Tb, [Fun(Ha, Hb)|Res]). but this seems to be general enough to be found in a library. Or maybe list comprehensions could be used in a clever way? thanks in advance, Vlad From tobbe@REDACTED Thu Sep 18 22:00:34 2003 From: tobbe@REDACTED (Torbjorn Tornkvist) Date: Thu, 18 Sep 2003 22:00:34 +0200 Subject: Enhanced type guard syntax] In-Reply-To: References: <004101c37e15$08ef7670$55ea1ec4@moneymaker> Message-ID: <3F6A0EE2.8080409@bluetail.com> ...packages...p/arametrized modules./..new guard syntax.. Perhaps it is time to remove the cobweb from the good old discussion topic of creating a new language 'Erlang2' (i.e Erlang done right). Perhaps a little switch to the compiler, in a transition phase + some automated conversion tool: Erlang -> E2 ...etc... Cheers , Tobbe From joachim.durchholz@REDACTED Thu Sep 18 22:02:26 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Thu, 18 Sep 2003 22:02:26 +0200 Subject: Enhanced type guard syntax] In-Reply-To: <001701c37dde$6d782d30$a22d1081@ituniv398> References: <3F697CCB.6000603@erix.ericsson.se> <3F69955D.2000806@futuresource.com> <001701c37dde$6d782d30$a22d1081@ituniv398> Message-ID: <3F6A0F52.8050408@web.de> Thomas Arts wrote: > [...] there was a philosophy that all guards should be executable in > constant time. This philosophy doesn't work out IMHO. Either, the guard is used as a selector. Then, if the guard is disallowed, people are going to write the exactly same non-constant-time code into the condition of an "if" statement, and nothing is won. Or the guard is used as a precondition. In that case, it shouldn't be a guard (but an assert statement or something - particularly, something that can be switched off for production code). Just my 2c. Regards, Jo From joachim.durchholz@REDACTED Thu Sep 18 22:23:45 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Thu, 18 Sep 2003 22:23:45 +0200 Subject: Enhanced type guard syntax] In-Reply-To: <004101c37e15$08ef7670$55ea1ec4@moneymaker> References: <004101c37e15$08ef7670$55ea1ec4@moneymaker> Message-ID: <3F6A1451.3010102@web.de> Valentin wrote: > For example, when we say ONE, we can write it as "1" or > "one" -- it wouldn't change the meaning, right? I think two things are getting conflated here: guards and preconditions. A guard is a kind of selector: the first implementation that has guards that match a given set of parameters is chosen. (In OO, all guards are on "typeof (first argument) <= typeof (first parameter)", so, in a sense, Erlang is indeed OO, but not on the message level *grin*.) If a given function has the wrong guards, the system will try another one, it will not fail. A precondition is unrelated to implementation. If the precondition fails, the caller has done something evil. This is things like calling sqrt with a negative argument, or, say, bank transfers with identical source and destination accounts. Any routine added that has a matching guard is simply wrong, it violates the contract that's supposed to go with the function of that description. Preconditions are valuable. Both as a kind of built-in unit test, and as a documentation aid. For testing, have the system compile the stuff with precondition checking enabled. For extra convenience, have the system compile them in anyway, and have them activated and deactivated by the run-time system. For generous convenience, have them activated and deactivated on a per-module or even per-function basis :-) (oh, and activate and deactivate them in the *calling* places, you usually want to debug the caller if you're checking precondition violations *g*) For documentation, it's simply both more precise and concise to have sqrt (X >= 0.0) instead of the verbose and natural-language all-too-often-fuzzy sqrt (X) %% X must be >= 0.0 Syntax ideas (just thinking loudly): Ideally, one would use something like function (X/guard) where "guard" is a fun() that accepts a single parameter, and returns True or False. For example, this would allow one to write stuff like is_real (X) and X >= 0.0 Unfortunately, taking out the X and getting this into a fun() is going to be *very* ugly. Too much syntactic cruft around here. Haskell solves the issue far more elegantly IMHO: any "incomplete" expression (which is an expression missing its last parameter) is automatically a fun(). The above as a fun() would then look like this: function (X / is_real and ('>=' 0)) where the constituents are: '>=' is the ordinary >= operator, just as a function of two parameters (i.e. you'd use this as '>=' 0 X to mean "0 >= X"); this is just syntactic sugar to convert the >= symbol from an operator into a function name. '>=' is a function of two parameters. In the above, the first parameter is given, yielding the function ('>=' 0), which is the function that returns True if its only parameter is greater than or equal to zero. is_real is just the name of a function, a one-parameter function that takes a single parameter. "and" is actually and/3, not the ordinary and/2. It take two single-parameter functions and a value; when called, it feeds the value to the functions and returns the logical AND of the two function result. (I'm not sure whether the compiler can be made to recognize that the "and" in the "is_real and ('>=' 0)" bit actually is and/3. Maybe some syntactic sugar is required. Well, I'm just thinking loudly anyway, without any claims to relevance *g*.) Hmm... no, it won't do. Erlang identifies functions by name and parameter count. If I write "foo X", the compiler expects it to be a call to foo/1, not a scantily clad foo/2 missing its second parameter. We'd need something like an extra "dummy" parameter, something like "foo X _". In the above, this would be function (X / is_real (_) and ('>=' 0 _)) or even function (X / is_real (_) and 0 <= _) which isn't much of an advantage over function (X / is_real (X) and 0 <= X) but remember that parameter names can be *much* longer than a single character :-) Anyway, on to another aspect: guards that involve multiple parameters. For a contrived example, assume distribute_percentages (X, Y, Z) %% X + Y + Z must sum up to 100. I'd prefer to write this as distribute_percentages ( X / in_range (0, 100, _), Y / in_range (0, 100, _), Z / in_range (0, 100, _) and X + Y + Z = 100.0) (See how the formalization forced me to become quite explicit about what a "percentage is?) Just my 2c. Regards, Jo From klacke@REDACTED Thu Sep 18 23:51:07 2003 From: klacke@REDACTED (Klacke) Date: Thu, 18 Sep 2003 23:51:07 +0200 Subject: Enhanced type guard syntax] In-Reply-To: <20030918080921.3ebe542e.cpressey@catseye.mine.nu> References: <20030918080921.3ebe542e.cpressey@catseye.mine.nu> Message-ID: <20030918215106.GA12828@bluetail.com> On Thu, Sep 18, 2003 at 08:09:21AM -0700, Chris Pressey wrote: > I think you CAN throw "when" completely away IF you take this new syntax > proposal to its logical extreme. > > foo(X, Y) when X == 2*Y > > becomes > > foo(X == 2 * Y) > Bad, uncomprehensible. I don't see the point in this new propasal at all. /klacke -- Claes Wikstrom -- Caps lock is nowhere and Alteon WebSystems -- everything is under control http://www.bluetail.com/~klacke cellphone: +46 70 2097763 From cpressey@REDACTED Fri Sep 19 00:16:37 2003 From: cpressey@REDACTED (Chris Pressey) Date: Thu, 18 Sep 2003 15:16:37 -0700 Subject: erlc (R9C) hangs when last line is is a comment missing EOL In-Reply-To: <3F69EF72.1010402@manderp.freeserve.co.uk> References: <20030917193704.146f0c51.cpressey@catseye.mine.nu> <3F6946D3.9060505@manderp.freeserve.co.uk> <20030918101805.39512802.cpressey@catseye.mine.nu> <3F69EF72.1010402@manderp.freeserve.co.uk> Message-ID: <20030918151637.4e9a5432.cpressey@catseye.mine.nu> On Thu, 18 Sep 2003 18:46:26 +0100 Peter-Henry Mander wrote: > > Chris Pressey wrote: > > On Thu, 18 Sep 2003 06:46:59 +0100 > > Peter-Henry Mander wrote: > > > >>I've seen this on SuSE 8.2 linux too. There's an easy work-around > >(-: > > > > How very pragmatic of you to suggest that :) > > How very magnaminous of you to say so (: > > Sorry chris, please excuse my flippancy. I made a note of this on the > list before, but it sank without trace, probably because there _is_ a > trivial work-around and so it's not considered a problem. 'Sokay... I'm just in a bad mood because, after making that change, erlc started to hang on *all* source files, so I had to reinstall R9C! So, word to the wise: don't make the same change I did. Yes, it's too small a bug to worry about, but - well, I don't mind things crashing (much), but it annoys me when they hang, is all... -Chris From cpressey@REDACTED Fri Sep 19 00:24:41 2003 From: cpressey@REDACTED (Chris Pressey) Date: Thu, 18 Sep 2003 15:24:41 -0700 Subject: Enhanced type guard syntax] In-Reply-To: <3F6A0F52.8050408@web.de> References: <3F697CCB.6000603@erix.ericsson.se> <3F69955D.2000806@futuresource.com> <001701c37dde$6d782d30$a22d1081@ituniv398> <3F6A0F52.8050408@web.de> Message-ID: <20030918152441.2b2d7037.cpressey@catseye.mine.nu> On Thu, 18 Sep 2003 22:02:26 +0200 Joachim Durchholz wrote: > Thomas Arts wrote: > > [...] there was a philosophy that all guards should be executable in > > constant time. > > This philosophy doesn't work out IMHO. > Either, the guard is used as a selector. Then, if the guard is > disallowed, people are going to write the exactly same > non-constant-time code into the condition of an "if" statement, and > nothing is won. Or the guard is used as a precondition. In that case, > it shouldn't be a guard (but an assert statement or something - > particularly, something that can be switched off for production code). > > Just my 2c. > > Regards, > Jo Sing it, brother! A much nicer world would be: 1) the programmer writes whatever code they want in the "when" test 2) the compiler analyzes that code 3) whatever parts of it that have side-effects are rejected 4) whatever parts of it are constant-time are used as the guard 5) whatever parts of it are non-constant-time are factored out into a "case" statement But that sort of requires that a) compiler-writers are well paid and b) the language is optimized for maintainability over efficiency... which only ever seem to hold true in my private little world. -Chris From richardc@REDACTED Fri Sep 19 00:41:23 2003 From: richardc@REDACTED (Richard Carlsson) Date: Fri, 19 Sep 2003 00:41:23 +0200 (MET DST) Subject: list handling functions In-Reply-To: References: Message-ID: On Thu, 18 Sep 2003, Vlad Dumitrescu wrote: > Are there any ways to simply express a 'map' (or similar) function > that iterates over several lists at once? I use something like > > map2(Fun, A, B) -> > map2(Fun, A, B, []). > > map2(Fun, [], _, Res) -> > lists:reverse(Res); > map2(Fun, _, [], Res) -> > lists:reverse(Res); > map2(Fun, [Ha|Ta],[Hb|Tb],Res)-> > map2(Fun, Ta, Tb, [Fun(Ha, Hb)|Res]). > > but this seems to be general enough to be found in a library. Or maybe > list comprehensions could be used in a clever way? I think the "standard" (but less efficient) solution is to first use a "zip" function on the two lists, creating a single list of 2-tuples (in most list libraries you'll also find a zip3 function for zipping 3 lists, and in some cases there are zip4...zip9 as well). Then you just do a normal "map" on the tuples. Your map2 can be viewed as the result of a deforestation-style optimization of zip+map. /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ "Having users is like optimization: the wise course is to delay it." -- Paul Graham From jay@REDACTED Fri Sep 19 04:08:24 2003 From: jay@REDACTED (Jay Nelson) Date: Thu, 18 Sep 2003 19:08:24 -0700 Subject: Building OTP R9C-0 on OpenBSD 3.3 Message-ID: <4.2.2.20030918190111.00d8be30@duomark.com> I have been struggling with Rick Pettit's solution to the OpenBSD 3.3 build problem. http://www.erlang.org/ml-archive/erlang-questions/200308/msg00096.html It was a little more complicated because of two things: 1) The configure script detects OpenSSL by looking for openssl.h which is located in /usr/include/openssl 2) The OPENSSL_CMD is /usr/sbin/openssl Just saying --with-ssl=/usr/include/openssl cannot handle both cases, nor does Rick's change to make SSL_BINDIR $dir/sbin seem to work completely. I had a stock standard OpenBSD 3.3 and couldn't get anything to work until I had move 'make' out of the way and symbolically linked 'gmake' to be make (after downloading the gmake code since it doesn't install by default). I will be upgrading to OpenBSD 3.4 (stock standard) in November and can test out any new patches. If one of the developers needs an OpenBSD login account I can provide one once I finish configuring my firewall this weekend. jay From vlad_dumitrescu@REDACTED Fri Sep 19 08:40:07 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Fri, 19 Sep 2003 08:40:07 +0200 Subject: Enhanced type guard syntax] References: Message-ID: > foo(A/integer, B/integer) -> > A * B. > > {X/float, Y/float} = graph:coordinates(), *** I think records should also be encompassed by this notation. But how to extend it to allow specification of a record name? foo(A/record#myRecord) -> foo(A/#myRecord) -> First one is more consistent with the parallel to the is_XXX bifs, but longer. *** Valentin wrote: >Inability to comprehend the value that this syntax would add makes me think >that the whole thing is about ideology and programming puritanism. As I see it, it's only syntactic sugar. The value is most visible when the only guards are type declarations, and when there are many parameters with longish names. myFun(FirstArgument, SecondArgument, ThirdArgument) when is_integer(FirstArgument), is_float(SecondArgument), is_list(ThirdArgument) -> myFun(FirstArgument/integer, SecondArgument/float, ThirdArgument/list) -> regards, /Vlad From tobbe@REDACTED Fri Sep 19 08:44:33 2003 From: tobbe@REDACTED (Torbjorn Tornkvist) Date: Fri, 19 Sep 2003 08:44:33 +0200 Subject: New stuff Message-ID: <3F6AA5D1.9010509@bluetail.com> HI, JFYI: Some (new) Erlang applications has been released: * Bluetail Ticket Tracker 4.0.1 , http://btt.sourceforge.net/ (Major rewrite compared to 3.1, now using Yaws.) * eldap , in the jungerl-cvs (LDAP client with TLS support) Cheers , Tobbe From erlang@REDACTED Fri Sep 19 08:57:29 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Fri, 19 Sep 2003 07:57:29 +0100 Subject: kill "if" and "case" instead! [was Re: Enhanced type guard syntax] In-Reply-To: References: Message-ID: <3F6AA8D9.8010803@manderp.freeserve.co.uk> Hi Joe and the Gurus, Joe Armstrong wrote: > Adding guards like this violates one of my favorite design > meta-principles: > > " If you add something to a language you have to chuck something > away " > > What are we going to chuck away? > > Well not "when ->" ... Maybe I just weird, but I don't find "when ->" offensive in the least. What's fundamentally wrong with it? It does a lot that can't be done otherwise, and seems to me to be othogonal to other language features. Syntactic sugar only makes a language fat. > Can we please start checking stuff away to make the language simple. In this case, may I propose that "if" and "case" were stuffed into the blender? They're _not_ orthogonal to other features! I cannot find any solid argument toward keeping and using them when writing equivalent code using functions alone makes (at least my) code much less prone to the Dreaded Indent pushing against the right margin. Not mentioning that the resulting function names can be well chosen too. > To hasten this process I'd like to add a new declaration to the > the language. > > All modules should start. > > -needsErlangVersion(N). > > Where N is the language version. Yes. I like this idea. In its absence, does it default to the version of todays Erlang? > They type y - and the system gets the latest version of the system > and installs it for them :-) That sounds horribly like Windows Update! Surely we can assume that users know where to get the latest version of Erlang? Or am I being presumtious? > Then once we have got the versioning in we can start chucking things > away. ... > You only need spawn(fun() -> ...) As I discovered recently, it's much cleaner. Yes, I'm a slow learner, (-: but I haven't had the benefit of a good training course )-: Bloody finances! Pete. From thomas.arts@REDACTED Fri Sep 19 09:43:50 2003 From: thomas.arts@REDACTED (Thomas Arts) Date: Fri, 19 Sep 2003 09:43:50 +0200 Subject: Enhanced type guard syntax] References: <3F697CCB.6000603@erix.ericsson.se><3F69955D.2000806@futuresource.com><001701c37dde$6d782d30$a22d1081@ituniv398><3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> Message-ID: <00a901c37e81$c4bff020$a22d1081@ituniv398> In the discussion on the type guard syntax I am missing the vision of what the type language should look like. Sure, we have the basic types and it all looks nice for integers and atoms.... but before you introduce a new syntax for something that is already exist, why not give it a thought what you want to achieve with it? A new notiation does not give you new possibilities in type checking! In particular one should consider whether one would allow guards with user defined types or guards with argumented types, polymorphic types, etc. For example: is f(X) when list(integer(X)) -> a good notation to express that X should be a list of integers? would that translate into f(X/list(integer)) ? is f(X,Y) when dictionary(K,V)(X), K(Y) -> a good notation for a dictionary of key value pairs with polymorphic type K for keys and V for values and a binding of the key type for the second argument of the funtion? would that be f(X/dictionary(K,V), Y/K) ? is f(X/list/list) a notation for list of list or should it be f(X/list(list)), in which case the type notation for list is both a constant and a unary function. is it possible to catch in a type notation: f(X) when 10 by f(X/[10..20]) ? My advice is to first discuss a suitable type language, see if that is realizable without performance penalties and then propose a syntactic sugar notation for it. One more remark, in the typed lambda calculus they use a type definition along with the variable in the same style as proposed, but they use : instead of /. I would really be in favour to use that much more standard notation, thus f(X:list(A), Y:A) -> ... One can use the same notation to give types to functions, as type annotations that can be checked by a compiler (without confusing it with devision) It will, though, be confused with module application. An alternative therefor is :: Semantically the : is "is element of" and a small epsilon could be used instead. However, we want to keep the ascii character set as convention, I guess. sort([]:list(A)) -> []:list(A); sort([X|Xs]:list(A)) -> ([ Y:A || Y<-Xs, Y, <3F6946D3.9060505@manderp.freeserve.co.uk>, <20030918101805.39512802.cpressey@catseye.mine.nu> Message-ID: Here's a "diff -c" of the fix to be relased in R9C-1. There is also a fix on erl_pp that is not really necessary, but caused the hanging. This fix makes the scan's ok so the error in erl_pp is not triggered. If this fix does not work, let me know. / Raimo Niskanen, Erlang/OTP, Ericsso AB *** /clearcase/otp/erts/lib/stdlib/src/erl_scan.erl@@/main/release/r9c_otp_4787/0 Thu Aug 28 10:41:22 2003 --- /clearcase/otp/erts/lib/stdlib/src/erl_scan.erl@@/main/release/r9c_otp_4787/LATEST Wed Sep 3 13:38:53 2003 *************** *** 558,564 **** scan_comment([_|Cs], Stack, Toks, Pos, State, Errors) -> scan_comment(Cs, Stack, Toks, Pos, State, Errors); scan_comment([], Stack, Toks, Pos, State, Errors) -> ! more([], Stack, Toks, Pos, State, Errors, fun scan_comment/6). --- 558,566 ---- scan_comment([_|Cs], Stack, Toks, Pos, State, Errors) -> scan_comment(Cs, Stack, Toks, Pos, State, Errors); scan_comment([], Stack, Toks, Pos, State, Errors) -> ! more([], Stack, Toks, Pos, State, Errors, fun scan_comment/6); ! scan_comment(Eof, _Stack, Toks, Pos, State, Errors) -> ! done(Eof, Errors, Toks, Pos, State). Chris Pressey wrote: > On Thu, 18 Sep 2003 06:46:59 +0100 > Peter-Henry Mander wrote: > > >>I've seen this on SuSE 8.2 linux too. There's an easy work-around (-: > > > How very pragmatic of you to suggest that :) > > There are similar errors on these types of files with file:consult/1, > file:eval/1, and erl_scan:string/1. > > I think I located the problem: erl_scan:scan_comment/6 doesn't have a > clause for when the first argument is just 'eof'. I added one that > calls done(Eof, [], Toks, Pos, eos), but it only has limited success > (erl_scan:string/1 no longer crashes, but the other still do.) > > -Chris > > >>Chris Pressey wrote: >> >>>Try this: >>> >>> >>>-module(blah). >>>%%% BEGIN blah %%% >>>-export([foo/0]). >>>foo() -> bar. >>>%%% END of blah %%% >>> ^ do not include an EOL here. >>> >>> >>># erlc foo.erl >>><> >>> >>>This happens for me both on FreeBSD-4.9 PRERELEASE and Windows 98. >>>(Also, I can't seem to gracefully kill erlc on Windows 98 when this >>>happens - Ctrl-C gives me the menu, but the 'a' option doesn't >>>work.) >>> >>>This only seems to happen when the last line is a comment AND is >>>missing an EOL. >>> >>>-Chris >>> >>> >> >> > > From vances@REDACTED Fri Sep 19 09:53:48 2003 From: vances@REDACTED (Vance Shipley) Date: Fri, 19 Sep 2003 03:53:48 -0400 Subject: kill "if" and "case" instead! [was Re: Enhanced type guard syntax] In-Reply-To: <3F6AA8D9.8010803@manderp.freeserve.co.uk> References: <3F6AA8D9.8010803@manderp.freeserve.co.uk> Message-ID: <20030919075348.GB25374@frogman.motivity.ca> } Not mentioning that the resulting function names can be well chosen too. I get stuck thinking about what to name things. foo2, foo3, foo4 are easy enough but anything else leaves me idle pondering how a name should be chosen. I like to use funs because I don't need to name them or if I do I can call them F or Fun. -Vance On Fri, Sep 19, 2003 at 07:57:29AM +0100, Peter-Henry Mander wrote: } } In this case, may I propose that "if" and "case" were stuffed into the } blender? They're _not_ orthogonal to other features! } } I cannot find any solid argument toward keeping and using them when } writing equivalent code using functions alone makes (at least my) code } much less prone to the Dreaded Indent pushing against the right margin. } Not mentioning that the resulting function names can be well chosen too. From erlang@REDACTED Fri Sep 19 10:31:03 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Fri, 19 Sep 2003 09:31:03 +0100 Subject: Enhanced type guard syntax] In-Reply-To: <00a901c37e81$c4bff020$a22d1081@ituniv398> References: <3F697CCB.6000603@erix.ericsson.se><3F69955D.2000806@futuresource.com><001701c37dde$6d782d30$a22d1081@ituniv398><3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> <00a901c37e81$c4bff020$a22d1081@ituniv398> Message-ID: <3F6ABEC7.3090903@manderp.freeserve.co.uk> Hi Gurus, Maybe thinking about how to achieve some form of parameter checking using existing pattern matching language features will put some kind of (skewed) perspective on the problem. If you _need_ to know what type of parameter is being given as an argument, would it be more explicit and practical to simply use tagged tuples? > is f(X) when list(integer(X)) -> > a good notation to express that X should be a list of integers? perhaps this: f({list_of_integers,X}) -> will provide a strong enough guard to to prevent illegal use of this function. > is f(X,Y) when dictionary(K,V)(X), K(Y) -> > a good notation for a dictionary of key value pairs with > polymorphic type K for keys and V for values and a binding > of the key type for the second argument of the funtion? again, maybe this will do the job: f({dictionary_of_key_value_pairs,X},{key_for_dictionary,Y}) -> (In practice I would think of using a less verbose version!) After all, type-checking languages are only offering a limited kind of pattern matching, aren't they? This scheme also makes it clear that {kelvin,RealNumber} is what it says it is, not just an abstract numeric type for example. A very desirable feature in my opinion. (Combine that with "when float(RealNumber), RealNumber >= 0" to add belt and braces). Can someone please write a counter-argument and find the leaks in this idea, to see if it holds water? Pete. Thomas Arts wrote: > In the discussion on the type guard syntax I am missing > the vision of what the type language should look like. > Sure, we have the basic types and it all looks nice for > integers and atoms.... but before you introduce a new > syntax for something that is already exist, why not give it > a thought what you want to achieve with it? > > A new notiation does not give you new possibilities in > type checking! In particular one should consider whether > one would allow guards with user defined types or guards > with argumented types, polymorphic types, etc. > > For example: > > is f(X) when list(integer(X)) -> > a good notation to express that X should be a list of integers? > > would that translate into f(X/list(integer)) ? > > is f(X,Y) when dictionary(K,V)(X), K(Y) -> > a good notation for a dictionary of key value pairs with > polymorphic type K for keys and V for values and a binding > of the key type for the second argument of the funtion? > would that be > f(X/dictionary(K,V), Y/K) ? > > is f(X/list/list) a notation for list of list or should it be > f(X/list(list)), in which case the type notation for list is both > a constant and a unary function. > > is it possible to catch in a type notation: > f(X) when 10 > by f(X/[10..20]) ? > > My advice is to first discuss a suitable type language, see if that > is realizable without performance penalties and then propose a > syntactic sugar notation for it. > > One more remark, in the typed lambda calculus they use a type > definition along with the variable in the same style as proposed, > but they use : instead of /. I would really be in favour to use that much > more standard notation, thus f(X:list(A), Y:A) -> ... > One can use the same notation to give types to functions, as type > annotations that can be checked by a compiler (without confusing > it with devision) It will, though, be confused with module application. > An alternative therefor is :: > Semantically the : is "is element of" and a small epsilon could be used > instead. However, we want to keep the ascii character set as convention, > I guess. > > sort([]:list(A)) -> > []:list(A); > sort([X|Xs]:list(A)) -> > ([ Y:A || Y<-Xs, Y [ Y:A || Y<-Xs, X= > these annotations help the type checker, if available and can be left out > in compiling for production code. > > /Thomas > > --- > Dr Thomas Arts > Program Manager > Software Engineering and Management > IT-university in Gothenburg > Box 8718, 402 75 Gothenburg, Sweden > http://www.ituniv.se/ > > Tel +46 31 772 6031 > Fax +46 31 772 4899 > > > > From thomas.arts@REDACTED Fri Sep 19 10:47:59 2003 From: thomas.arts@REDACTED (Thomas Arts) Date: Fri, 19 Sep 2003 10:47:59 +0200 Subject: Enhanced type guard syntax] References: <3F697CCB.6000603@erix.ericsson.se><3F69955D.2000806@futuresource.com><001701c37dde$6d782d30$a22d1081@ituniv398><3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> <00a901c37e81$c4bff020$a22d1081@ituniv398> <3F6ABEC7.3090903@manderp.freeserve.co.uk> Message-ID: <015b01c37e8a$ba8a0560$a22d1081@ituniv398> > perhaps this: > > f({list_of_integers,X}) -> this is inflexible for a type checker. The tuple notation is fine, but the verbose way of writing the atom hides the semantics. This is very clear in: > f({dictionary_of_key_value_pairs,X},{key_for_dictionary,Y}) -> How do you know that there is a relation between the key in the first atom and the key in the second atom? They might refer to completely different things. That is where variables come in. /Thomas From vlad_dumitrescu@REDACTED Fri Sep 19 10:53:07 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Fri, 19 Sep 2003 10:53:07 +0200 Subject: Enhanced type guard syntax] References: <3F697CCB.6000603@erix.ericsson.se><3F69955D.2000806@futuresource.com><001701c37dde$6d782d30$a22d1081@ituniv398><3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> <00a901c37e81$c4bff020$a22d1081@ituniv398> <3F6ABEC7.3090903@manderp.freeserve.co.uk> Message-ID: While I'm no guru, I'll give my 2c From: "Peter-Henry Mander" > If you _need_ to know what type of parameter is being given as an > argument, would it be more explicit and practical to simply use tagged > tuples? > > > is f(X) when list(integer(X)) -> > > a good notation to express that X should be a list of integers? > > perhaps this: > > f({list_of_integers,X}) -> > > will provide a strong enough guard to to prevent illegal use of this > function. The idea is certainly interesting, but one problem that I can see is that one has to either - return {list_of_integers, Value} from all functions that compute such a beast or - be forced to write Result = fun_that_returns_a_list_of_integers(), f({list_of_integers, Result}), instead of f(fun_that_returns_a_list_of_integers()), The big advantage of using the real types and not tags is that they are present in the runtime, while invisible in the code. regards, Vlad From erlang@REDACTED Fri Sep 19 10:55:41 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Fri, 19 Sep 2003 09:55:41 +0100 Subject: Enhanced type guard syntax] In-Reply-To: <015b01c37e8a$ba8a0560$a22d1081@ituniv398> References: <3F697CCB.6000603@erix.ericsson.se><3F69955D.2000806@futuresource.com><001701c37dde$6d782d30$a22d1081@ituniv398><3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> <00a901c37e81$c4bff020$a22d1081@ituniv398> <3F6ABEC7.3090903@manderp.freeserve.co.uk> <015b01c37e8a$ba8a0560$a22d1081@ituniv398> Message-ID: <3F6AC48D.4020605@manderp.freeserve.co.uk> Okay, how about going to extremes: f({{dictionary,store},X},{{dictionary,key},Y}) -> Now you know they are related (-: and you can do a general case: f({{dictionary,_whatever},Thing}) -> I would agree that my example is not practical, but it may seed another idea from someone? Pete. Thomas Arts wrote: >>perhaps this: >> >> f({list_of_integers,X}) -> > > > this is inflexible for a type checker. The tuple notation is fine, but > the verbose way of writing the atom hides the semantics. > This is very clear in: > > >> f({dictionary_of_key_value_pairs,X},{key_for_dictionary,Y}) -> > > > How do you know that there is a relation between the key in the first atom > and the key in the second atom? They might refer to completely different > things. That is where variables come in. > > /Thomas > > > > From erlang@REDACTED Fri Sep 19 11:06:18 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Fri, 19 Sep 2003 10:06:18 +0100 Subject: Enhanced type guard syntax] In-Reply-To: References: <3F697CCB.6000603@erix.ericsson.se><3F69955D.2000806@futuresource.com><001701c37dde$6d782d30$a22d1081@ituniv398><3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> <00a901c37e81$c4bff020$a22d1081@ituniv398> <3F6ABEC7.3090903@manderp.freeserve.co.uk> Message-ID: <3F6AC70A.3040609@manderp.freeserve.co.uk> Hi Vlad, Vlad Dumitrescu wrote: [...] > The idea is certainly interesting, but one problem that I can see is that one > has to either > > - return {list_of_integers, Value} from all functions that compute such a beast Not necessarily, for example: sum({list_of_integers, Value}) -> ... {integer,Sum}. or sum({list_of_integers, Value}) -> ... Sum. is a design issue. Or am I missing your point? This scheme must be applied throughout where "types" are required for it to work, and I agree that it can become tiresome to write, but design it right and it will save some pain later. If you return tagged types, it will force users of the function to honor the type scheme, and isn't that what the goal is? Pete. > or > > - be forced to write > Result = fun_that_returns_a_list_of_integers(), > f({list_of_integers, Result}), > instead of > f(fun_that_returns_a_list_of_integers()), > > The big advantage of using the real types and not tags is that they are present > in the runtime, while invisible in the code. > > regards, > Vlad > > From mike@REDACTED Fri Sep 19 11:07:40 2003 From: mike@REDACTED (Mike Williams) Date: 19 Sep 2003 09:07:40 GMT Subject: Enhanced type guard syntax] References: <3F697CCB.6000603@erix.ericsson.se> Message-ID: Someone (I think it was Joe) said that if you add something to a language you should also be prepared to take something away. I.e. you don't want to let the language become a monster like PL1 (or Perl). So, if we were to add Kenneth's syntax, what will be take remove? /mike From vlad_dumitrescu@REDACTED Fri Sep 19 11:23:12 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Fri, 19 Sep 2003 11:23:12 +0200 Subject: Enhanced type guard syntax] References: <3F697CCB.6000603@erix.ericsson.se><3F69955D.2000806@futuresource.com><001701c37dde$6d782d30$a22d1081@ituniv398><3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> <00a901c37e81$c4bff020$a22d1081@ituniv398> <3F6ABEC7.3090903@manderp.freeserve.co.uk> <3F6AC70A.3040609@manderp.freeserve.co.uk> Message-ID: From: "Peter-Henry Mander" > > - return {list_of_integers, Value} from all functions that compute such a beast > > Not necessarily, for example: > sum({list_of_integers, Value}) -> ... {integer,Sum}. > or > sum({list_of_integers, Value}) -> ... Sum. > is a design issue. > > Or am I missing your point? No it was my point :-) What I was thinking about was that using this scheme from the very start of the development (i.e. prototyping) would make it no nolger be rapid, which is a very good thing about Erlang. To introduce the tags at a later stage is cumbersome. > This scheme must be applied throughout where "types" are required for it > to work, and I agree that it can become tiresome to write, but design it > right and it will save some pain later. > > If you return tagged types, it will force users of the function to honor > the type scheme, and isn't that what the goal is? I am not sure if forcing developers to do things in a more convoluted way is always a good thing, even if there are gains somewhere else. What I think of is the Java exception declaration for each method - it is useful in some ways, but a pain while developing. To sum my point, I think the idea is interesting and I hope it will lead to something really useful. /Vlad From svg@REDACTED Fri Sep 19 11:56:55 2003 From: svg@REDACTED (Vladimir Sekissov) Date: Fri, 19 Sep 2003 15:56:55 +0600 (YEKST) Subject: list handling functions In-Reply-To: References: Message-ID: <20030919.155655.74729923.svg@surnet.ru> Good day, In the attachment is my library module for list of lists processing. In your case it will be applyn: 8> wslib.listn:applyn(fun (A, B, C) -> A+B+C end,[[1,2,3], [4,5,6], [7,8,9]]). [12,15,18] Best Regards, Vladimir Sekissov vlad_dumitrescu> Hi, vlad_dumitrescu> vlad_dumitrescu> Maybe tomorrow I will be ashamed to have asked a question whose answer is vlad_dumitrescu> obvious, but here it goes: vlad_dumitrescu> vlad_dumitrescu> Are there any ways to simply express a 'map' (or similar) function that vlad_dumitrescu> iterates over several lists at once? I use something like vlad_dumitrescu> vlad_dumitrescu> map2(Fun, A, B) -> vlad_dumitrescu> map2(Fun, A, B, []). vlad_dumitrescu> vlad_dumitrescu> map2(Fun, [], _, Res) -> vlad_dumitrescu> lists:reverse(Res); vlad_dumitrescu> map2(Fun, _, [], Res) -> vlad_dumitrescu> lists:reverse(Res); vlad_dumitrescu> map2(Fun, [Ha|Ta],[Hb|Tb],Res)-> vlad_dumitrescu> map2(Fun, Ta, Tb, [Fun(Ha, Hb)|Res]). vlad_dumitrescu> vlad_dumitrescu> but this seems to be general enough to be found in a library. Or maybe list vlad_dumitrescu> comprehensions could be used in a clever way? vlad_dumitrescu> vlad_dumitrescu> thanks in advance, vlad_dumitrescu> Vlad -------------- next part -------------- %%%---------------------------------------------------------------------- %%% File : listn.erl %%% Author : %%% Purpose : %%% Created : 12 Oct 2001 by %%%---------------------------------------------------------------------- -module(wslib.listn). -vsn('$Id\$'). -author('svg@REDACTED'). -export([listn/1, appendn/1, applyn/2, zip/2, zipn/1, unzip/1, unzipn/1]). -export([foldn/3, mapn/2]). -export([mk_list/1, split_on/2, split/2]). -import(.lists). %% %% listn([[1,2,3], [4,5,6], [7,8,9]]) ->[[1,4,7],[2,5,8],[3,6,9]] %% listn(Ls) -> [lists:reverse(L) || L <- foldn(fun (A, Acc) -> [A|Acc] end, [], Ls)]. %% %% appendn([[[1,2,3], [4,5,6], [7,8,9]], [[a,b,c], [d,e,f], [g, h, i]]]) -> %% [[1,2,3,a,b,c],[4,5,6,d,e,f],[7,8,9,g,h,i]] %% appendn(L) -> foldn(fun (A, Acc) -> Acc ++ A end, [], L). %% %% applyn(fun (A, B, C) -> A+B+C end, [[1,2,3], [4,5,6], [7,8,9]]) -> %% [12,15,18] %% applyn(Fun, LL) -> [apply(Fun, L) || L <- listn(LL)]. foldn(_, _, []) -> []; foldn(Fun, Acc0, Ls) -> foldn(Fun, Acc0, Ls, []). foldn(_, _, [[]|_], Ret) -> lists:reverse(Ret); foldn(Fun, Acc0, Ls, Ret) -> foldn(Fun, Acc0, [tl(L) || L <- Ls], [lists:foldl(Fun, Acc0, [hd(L) || L <- Ls])|Ret] ). %% %% mapn(fun (A, B, C) -> A+B+C end, [[1,2,3], [4,5,6], [7,8,9]]) -> %% [[[12,13,14],[13,14,15],[14,15,16]], %% [[13,14,15],[14,15,16],[15,16,17]], %% [[14,15,16],[15,16,17],[16,17,18]]] %% mapn(Fun, []) -> []; mapn(Fun, List) when list(List) -> mapn(Fun, List, []). mapn(Fun, [List], Args) -> lists:map(fun (E) -> apply(Fun, lists:reverse([E|Args])) end, List); mapn(Fun, [List|Rest], Args) -> lists:map(fun (E) -> mapn(Fun, Rest, [E|Args]) end, List). zip(L1, L2) -> zip(L1, L2, []). zip(L1, L2, Res) when L1 == []; L2 == [] -> lists:reverse(Res); zip([E1|Rest1], [E2|Rest2], Acc) -> zip(Rest1, Rest2, [{E1, E2}|Acc]). zipn(List) -> [list_to_tuple(L) || L <- listn(List)]. unzip(List) -> {L1, L2} = lists:foldl(fun ({E1, E2}, {Es1, Es2}) -> {[E1|Es1], [E2|Es2]} end, {[], []}, List), {lists:reverse(L1), lists:reverse(L2)}. unzipn(List) -> listn([tuple_to_list(T) || T <- List]). mk_list(V) when list(V) -> V; mk_list(V) -> [V]. split_on(Pos, L) when is_integer(Pos), Pos >= 0 -> split_on(Pos, L, []). split_on(0, Tail, Head) -> {lists:reverse(Head), Tail}; split_on(Num, [E|Rest], Acc) -> split_on(Num-1, Rest, [E|Acc]). split(Size, L) -> split(Size, L, []). split(Size, L, Acc) when length(L) =< Size -> lists:reverse([L|Acc]); split(Size, L, Acc) -> {H, T} = split_on(Size, L), split(Size, T, [H|Acc]). From erlang@REDACTED Fri Sep 19 12:28:43 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Fri, 19 Sep 2003 11:28:43 +0100 Subject: Enhanced type guard syntax] In-Reply-To: References: <3F697CCB.6000603@erix.ericsson.se><3F69955D.2000806@futuresource.com><001701c37dde$6d782d30$a22d1081@ituniv398><3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> <00a901c37e81$c4bff020$a22d1081@ituniv398> <3F6ABEC7.3090903@manderp.freeserve.co.uk> <3F6AC70A.3040609@manderp.freeserve.co.uk> Message-ID: <3F6ADA5B.6090604@manderp.freeserve.co.uk> Hi Vlad, Hi Thomas, Vlad said, answering me: >>Not necessarily, for example: >> sum({list_of_integers, Value}) -> ... {integer,Sum}. >>or >> sum({list_of_integers, Value}) -> ... Sum. >>is a design issue. >> >>Or am I missing your point? > > No it was my point :-) What I was thinking about was that using this scheme from > the very start of the development (i.e. prototyping) would make it no nolger be > rapid, which is a very good thing about Erlang. To introduce the tags at a later > stage is cumbersome. Ah, yes, but when prototyping I'm ready to scrap old ideas to introduce something better or more specific. Is it true that if the prototype has matured to the point where making changes is difficult, it is no longer really a suitable prototype? >>If you return tagged types, it will force users of the function to honor >>the type scheme, and isn't that what the goal is? > > I am not sure if forcing developers to do things in a more convoluted way is > always a good thing, even if there are gains somewhere else. I think that if the prototype demonstrates the need for stricter types, an experienced programmer/designer will introduce them as required, and avoid the pain later, unless of course the design decision was wrong. But if the _design_ is wrong, type checking won't help avoid the pain of making changes to correct it! The "convolution" is there for a purpose, and tagging makes the reason clear (if the name is well chosen). If the tagging is inappropriate, or doesn't permit nested categories of example (Thomas, did my answer of using n-tuples press any buttons?), or simply not necessary it can be changed or removed globally. But I'm sure that *adding* tags after creating a tagless design will be painful and error prone. It's a design decision that ought be made early, but it may be delayed until a simple prototype indicates the need for stricter parameter types. But looking at my own code, this tagging scheme isn't pervasive, and I get sufficient control over data with the few tags I've (carefully :-) chosen to not desire any extra type checking in the compiler. This may explain why I'm not sure I understand the type-strict argument properly. Thomas, I need your opinion on this, you've got an attentive student here :-) Pete. From vlad_dumitrescu@REDACTED Fri Sep 19 12:34:47 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Fri, 19 Sep 2003 12:34:47 +0200 Subject: Enhanced type guard syntax] References: <3F697CCB.6000603@erix.ericsson.se><3F69955D.2000806@futuresource.com><001701c37dde$6d782d30$a22d1081@ituniv398><3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> <00a901c37e81$c4bff020$a22d1081@ituniv398> <3F6ABEC7.3090903@manderp.freeserve.co.uk> <3F6AC70A.3040609@manderp.freeserve.co.uk> <3F6ADA5B.6090604@manderp.freeserve.co.uk> Message-ID: Just a short comment (for now :) From: "Peter-Henry Mander" > I think that if the prototype demonstrates the need for stricter types, > an experienced programmer/designer will introduce them as required, and > avoid the pain later, unless of course the design decision was wrong. What if the compiler will be able to optimize a lot more if supplied with type information? This has nothing to do with design, but depends on the specific compiler implementation. I feel there are several issues at stake and that I can't separate them properly, so I'll take my time to think over properly. /Vlad From thomas.arts@REDACTED Fri Sep 19 13:18:13 2003 From: thomas.arts@REDACTED (Thomas Arts) Date: Fri, 19 Sep 2003 13:18:13 +0200 Subject: Enhanced type guard syntax] References: <3F697CCB.6000603@erix.ericsson.se><3F69955D.2000806@futuresource.com><001701c37dde$6d782d30$a22d1081@ituniv398><3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> <00a901c37e81$c4bff020$a22d1081@ituniv398> <3F6ABEC7.3090903@manderp.freeserve.co.uk> <3F6AC70A.3040609@manderp.freeserve.co.uk> <3F6ADA5B.6090604@manderp.freeserve.co.uk> Message-ID: <018701c37e9f$b789ff40$a22d1081@ituniv398> Dear Peter > The "convolution" is there for a purpose, and tagging makes the reason > clear (if the name is well chosen). If the tagging is inappropriate, or > doesn't permit nested categories of example (Thomas, did my answer of > using n-tuples press any buttons?), or simply not necessary it can be > changed or removed globally. But I'm sure that *adding* tags after > creating a tagless design will be painful and error prone. I think this discussion is mixing up two ideas. 1) There is a proposal to write type guards in a different way 2) There is an older discussion, that people like to have some type checking support. W.r.t. 1) if you make a choice, my point was to realize that you might influence the possibilities for 2). The discussion between Vlad and Peter seems to rise from a misunderstanding between Static type checking and Dynamic type checking. Peter basically proposes to have tags for all types at runtime. In the present Erlang compiler, all basic types are already tagged, though not by tuples, but by the internal representation. That is why you can get an runtime type error when adding an integer to an atom. If you want to extend that principle with user defined types, you might do that by tuples and a lot of work, or add something to the internal representation. No matter how, you need a representation for it. Static type checking may use the same representation as the dynamic one, but checks at compile time whether there is a type conflict. At runtime there need not be any type information available, since you are guaranteed (by the checker) that you will never add an integer to an atom. In Erlang, I am convinced, you need a combination of dynamic and static type checking. Notation does not solve the type-check problem, but it can complicate it. Therefore, if you favour the type-guard notation that Kenneth proposed, I think you should realize the consequences for the type checking. Oh, and to answer Mike... one should definitely take away the type guards as they are today, therewith loosing backward compatibility. You can otherwise write stupid things like: f(X/integer) when string(X) -> .... /Thomas --- Dr Thomas Arts Program Manager Software Engineering and Management IT-university in Gothenburg Box 8718, 402 75 Gothenburg, Sweden http://www.ituniv.se/ Tel +46 31 772 6031 Fax +46 31 772 4899 From erlang@REDACTED Fri Sep 19 13:35:24 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Fri, 19 Sep 2003 12:35:24 +0100 Subject: Enhanced type guard syntax] In-Reply-To: <018701c37e9f$b789ff40$a22d1081@ituniv398> References: <3F697CCB.6000603@erix.ericsson.se><3F69955D.2000806@futuresource.com><001701c37dde$6d782d30$a22d1081@ituniv398><3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> <00a901c37e81$c4bff020$a22d1081@ituniv398> <3F6ABEC7.3090903@manderp.freeserve.co.uk> <3F6AC70A.3040609@manderp.freeserve.co.uk> <3F6ADA5B.6090604@manderp.freeserve.co.uk> <018701c37e9f$b789ff40$a22d1081@ituniv398> Message-ID: <3F6AE9FC.7030503@manderp.freeserve.co.uk> Thomas Arts wrote: > Dear Peter Hi Thomas, > If you want to extend that principle with user defined types, you > might do that by tuples and a lot of work, or add something to > the internal representation. No matter how, you need a representation > for it. > > Static type checking may use the same representation as the > dynamic one, but checks at compile time whether there is a > type conflict. At runtime there need not be any type information > available, since you are guaranteed (by the checker) that you > will never add an integer to an atom. Thanks for explaining that, I forgot the static/dynamic aspect. So (including aspects in an email to Vlad) this has an impact on:- 1) code correctness and checking during compilation, without added "binary-baggage" at runtime, 2) trapping exceptions at runtime, which is what tagging was meant to achieve, albeit clumsily, I concede. 3) optimisation (maybe?). From erlang@REDACTED Fri Sep 19 13:34:45 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Fri, 19 Sep 2003 12:34:45 +0100 Subject: Enhanced type guard syntax] In-Reply-To: References: <3F697CCB.6000603@erix.ericsson.se><3F69955D.2000806@futuresource.com><001701c37dde$6d782d30$a22d1081@ituniv398><3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> <00a901c37e81$c4bff020$a22d1081@ituniv398> <3F6ABEC7.3090903@manderp.freeserve.co.uk> <3F6AC70A.3040609@manderp.freeserve.co.uk> <3F6ADA5B.6090604@manderp.freeserve.co.uk> Message-ID: <3F6AE9D5.20706@manderp.freeserve.co.uk> Hi Vlad, You're right, there is the issue of optimisation, which may bear on some languages. But can you give an example of what optimisations would vastly improve Erlang performance? If straight-line dragster performance is an issue, maybe Erlang is the wrong tool? It's strengths are elsewhere. I'm using Erlang as a Megaco signalling stress tester, and Jove! It beats the pants off commercial testing tools because it's power is in concurrency, not so much in single-threaded speed. Maybe some elaborate and sophisticated data analysis on ordinary Erlang code would reveal optimisations that a simple human could not envisage? I would prefer a tool to do the grunt work and avoid me making mistaken "optimisation" judgements. Besides, if the algorithm is wrong anyway, then the programmer is the problem, not the language. So we have (as a first draft) type strictness for:- 1) code correctness and proof at compile time 2) trapping errors at runtime, 3) compiler code optimisation pass. Vlad Dumitrescu wrote: > Just a short comment (for now :) > > From: "Peter-Henry Mander" > >>I think that if the prototype demonstrates the need for stricter types, >>an experienced programmer/designer will introduce them as required, and >>avoid the pain later, unless of course the design decision was wrong. > > > What if the compiler will be able to optimize a lot more if supplied with type > information? This has nothing to do with design, but depends on the specific > compiler implementation. > > I feel there are several issues at stake and that I can't separate them > properly, so I'll take my time to think over properly. > > /Vlad > > From rpettit@REDACTED Fri Sep 19 16:48:44 2003 From: rpettit@REDACTED (Rick Pettit) Date: Fri, 19 Sep 2003 07:48:44 -0700 Subject: Building OTP R9C-0 on OpenBSD 3.3 In-Reply-To: <4.2.2.20030918190111.00d8be30@duomark.com> References: <4.2.2.20030918190111.00d8be30@duomark.com> Message-ID: <20030919144844.GA1103@vailsys.com> On Thu, Sep 18, 2003 at 07:08:24PM -0700, Jay Nelson wrote: > I have been struggling with Rick Pettit's solution to the > OpenBSD 3.3 build problem. > > http://www.erlang.org/ml-archive/erlang-questions/200308/msg00096.html > > It was a little more complicated because of two things: > > 1) The configure script detects OpenSSL by looking > for openssl.h which is located in /usr/include/openssl > > 2) The OPENSSL_CMD is /usr/sbin/openssl This is no different than the problems I had. The autotools stuff assumes that the openssl executable is $with_ssl/bin/openssl, whic is incorrect on OpenBSD. > Just saying --with-ssl=/usr/include/openssl cannot handle > both cases, nor does Rick's change to make SSL_BINDIR > $dir/sbin seem to work completely. You did not follow all the instructions (granted, I could have been a bit more specific on _which_ Makefile): I finally got R9C to build, after doing the following: 1) ./configure --with-ssl=/usr/include/openssl Configure succeeds, but build will fail as OPENSSL_CMD is incorrectly set to /usr/include/openssl/bin/openssl 2) manually modify appropriate Makefile to hard-code OPENSSL_CMD If you only follow step one, you get the problem you currently have. The lazy approach is to do the configure, then the build and let it fail trying to make certificates with openssl, then change the OPENSSL_CMD in the ssl Makefile, and run the build again. Of course the right thing to do would be to fix the configure stuff so that it looks in the right place by default on OpenBSD. It looks like you skipped step 2. I have had this built and running great for weeks now. > I had a stock standard OpenBSD 3.3 and couldn't get > anything to work until I had move 'make' out of the way > and symbolically linked 'gmake' to be make (after downloading > the gmake code since it doesn't install by default). Why not just run gmake? I did not have to symbolically link anything. In either case, if you have any more problems I would be more than happy to help. -Rick From rpettit@REDACTED Fri Sep 19 18:28:07 2003 From: rpettit@REDACTED (Rick Pettit) Date: Fri, 19 Sep 2003 09:28:07 -0700 Subject: Building OTP R9C-0 on OpenBSD 3.3 In-Reply-To: <4.2.2.20030918190111.00d8be30@duomark.com> References: <4.2.2.20030918190111.00d8be30@duomark.com> Message-ID: <20030919162807.GB1103@vailsys.com> On Thu, Sep 18, 2003 at 07:08:24PM -0700, Jay Nelson wrote: > I have been struggling with Rick Pettit's solution to the > OpenBSD 3.3 build problem. Ok, I just rebuilt OTP R9C-0 with the following steps on OpenBSD 3.3: 1) tar zxvf otp_src_R9C-0.tar.gz 2) patch otp_src_R9C-0/lib/os_mon/c_src/memsup.c memsup.c.openbsd-patch NOTE: see attachment for memsup.c.openbsd-patch 3) cd otp_src_R9C-0 4) ./configure --with-ssl=/usr/include/openssl NOTE: this will succeed, but the ssl Makefile will have OPENSSL_CMD set to /usr/include/openssl/bin/openssl, which is incorrect (needs to be /usr/sbin/openssl) 5) patch lib/ssl/examples/certs/i386-unknown-openbsd3.3/Makefile \ ssl-makefile-patch NOTE: see attachment for ssl-makefile-patch 6) gmake 7) sudo gmake install I apologize for not being more specific in my previous instructions. Again, although this method does work (just worked for me :-) it is NOT the right thing to do. The memsup.c.openbsd-patch would not be necessary if an #ifndef OpenBSD was wrapped around the header which should not be included on OpenBSD. Likewise, the autotools stuff could be modified so that openssl is found on stock OpenBSD boxes. Then, you could just follow the instructions in the README that ships with OTP and you would be just fine (sorry, with the exception that you run gmake not make). Hope this helps. -Rick -------------- next part -------------- 98d97 < #include -------------- next part -------------- 32c32 < OPENSSL_CMD = /usr/include/openssl/bin/openssl --- > OPENSSL_CMD = /usr/sbin/openssl From cpressey@REDACTED Fri Sep 19 17:52:58 2003 From: cpressey@REDACTED (Chris Pressey) Date: Fri, 19 Sep 2003 08:52:58 -0700 Subject: erlc (R9C) hangs when last line is is a comment missing EOL In-Reply-To: References: <3F6946D3.9060505@manderp.freeserve.co.uk> <3F6946D3.9060505@manderp.freeserve.co.uk> <20030918101805.39512802.cpressey@catseye.mine.nu> Message-ID: <20030919085258.43eabe36.cpressey@catseye.mine.nu> On Fri, 19 Sep 2003 09:44:58 +0200 Raimo Niskanen wrote: > Here's a "diff -c" of the fix to be relased in R9C-1. There is also a > fix on erl_pp that is not really necessary, but caused the hanging. > This fix makes the scan's ok so the error in erl_pp is not triggered. > > If this fix does not work, let me know. Thanks! The 'patch' program couldn't understand the patch for some reason, but once I made the change by hand, it worked beautifully, for both file:consult/1 and erlc. -Chris From mlogan@REDACTED Fri Sep 19 17:59:26 2003 From: mlogan@REDACTED (Martin J. Logan) Date: 19 Sep 2003 10:59:26 -0500 Subject: Enhanced type guard syntax] In-Reply-To: References: Message-ID: <1063987165.2708.1147.camel@dhcp-lom-194-186.futuresource.com> Erlang and concurrent programming relies on good programmer practice to create reliable, comprehensible programs. Many of these idioms are embodied in OTP. Still one can choose to use OTP or not, and if not still write reasonable programs. Some things are too scary to leave up to idiom and the good conscience of any erlang programmer. While more type checking would doubtless provide some benefit to the programmer user defined guards at the same time opens the door for real inconsistency and uncertainty if one is not well informed and painstaking in writing them. I call this with func(d, Arg). func(a, Arg) when user_side_effect(Arg) -> a; func(b, Arg) when user_side_effect(Arg) -> b; func(c, Arg) when user_side_effect(Arg) -> c; func(_, Arg) when user_side_effect(Arg) -> error. I assume that only the fourth function will ever be executed. I consequently assume the expressions associated with expression 4 is the only expression having the potential to influence the state or *significant* timing of my system. This assumption is based on the assumption that the people writing guard expressions are following the strict rules associated with writing such an expression. This would all go out the window if guards are not considered sacred anymore. If user defined guards were to be allowed some other language/context would have to be devised to write them. This language would provide the necessary safeguards - like no messaging or "put" calls and such. Basically it would not allow much past a basic declarative syntax for defining the structure of a thing and perhaps some ability to define these things recursively. Think we've seen this before in many other type systems. That is fine for erlang if anyone could ever implement it without crippling what is erlang. Having users create there own type system, in essence, for every function(user defined guards) seems like a no no. Cheers, Martin On Thu, 2003-09-18 at 08:57, Joe Armstrong wrote: > On Thu, 18 Sep 2003, Fredrik Linder wrote: > > > > foo(A/integer, B/integer) -> > > > A * B. > > > > > > {X/float, Y/float} = graph:coordinates(), > > > > This looks really really nice! > > > > Again, I'd like to ask for user-defined guards, as it would really enhance > > ... erlang(?). > > > > No - guards are extensions of patterns. They have to be simple, > so that a pattern matching compiler can do a good job on them. > > If we had user defined guards somebody will write: > > foo(X) when bar(X), a == b -> > ... > > Where bar(X) a user defined guard. > > Now what happens if somebody writes: > > bar(P) -> P ! a, true. > > But the guard fails (ie a==b) fails, did the message get sent????? > > Cheers > > /Joe > From cpressey@REDACTED Fri Sep 19 19:22:35 2003 From: cpressey@REDACTED (Chris Pressey) Date: Fri, 19 Sep 2003 10:22:35 -0700 Subject: Enhanced type guard syntax In-Reply-To: <3F6AE9FC.7030503@manderp.freeserve.co.uk> References: <3F697CCB.6000603@erix.ericsson.se> <3F69955D.2000806@futuresource.com> <001701c37dde$6d782d30$a22d1081@ituniv398> <3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> <00a901c37e81$c4bff020$a22d1081@ituniv398> <3F6ABEC7.3090903@manderp.freeserve.co.uk> <3F6AC70A.3040609@manderp.freeserve.co.uk> <3F6ADA5B.6090604@manderp.freeserve.co.uk> <018701c37e9f$b789ff40$a22d1081@ituniv398> <3F6AE9FC.7030503@manderp.freeserve.co.uk> Message-ID: <20030919102235.216f8fc3.cpressey@catseye.mine.nu> On Fri, 19 Sep 2003 12:35:24 +0100 Peter-Henry Mander wrote: > [...] > So (including aspects in an email to Vlad) this has an impact on:- > > 1) code correctness and checking during compilation, without added > "binary-baggage" at runtime, > > 2) trapping exceptions at runtime, which is what tagging was meant to > achieve, albeit clumsily, I concede. > > 3) optimisation (maybe?). Congratulations. What started out as a proposal for a frivolous but otherwise seemingly harmless piece of syntactic sugar, has blossomed into yet another a monstrously murky discussion on typing. (See Pete? You aren't the only one who can be flippant :) I think we are all missing something simple and obvious here, and getting hung up in relatively meaningless details. Here is my thought - Erlang doesn't need another type _checker_. Type checkers do not appeal to the laziness of Erlang programmers, who don't want to spell out stuff they already know! What Erlang needs is a type _inferencer_. (And if the inferencer can figure out other properties such as side-effectfulness, which shouldn't be too much extra difficultly, then all the better.) Note that I'm not suggesting that Erlang should "have [only] inferred types." I don't think such a concept makes much sense in Erlang. If you want to tell Erlang that X should be some type y, you should be able to tell it that (and a guard test is one way to do that.) But I think that a lot of the time, you actually don't need to do that. This is mostly an educated guess, but it seems like ~70% or more of the type consistency that _counts_ could be inferred by a pre-compile pass. This information could then be used to generate errors (at compile time *and* run time) and optimizations and documentation... and pretty kaliedoscope patterns for your screen-saver, if you like. Simple examples are easy to come by. If you have a function like hyp(A, B) -> math:sqrt(A * A + B * B). and you know the type signatures of *, +, and math:sqrt/1, you can pretty much instantly derive the type signature of hyp/2 (FLOAT x FLOAT -> FLOAT). Basically, you start with the assumption that every variable can be of any type, and you pare it down by looking at how it is used. The sets module would be handy for this, because it's all about sets of types. While you are doing this, you can also learn other things about functions - for example, a function is side-effectless only if all the functions and operators it calls are also side-effectless - so you can put this information in its signature, too. Constant-time is trickier, but I _think_ possibly still possible. (At least, I hope so.) Now, guards (however they're notated) suddenly play a more important role in things - they tell the type inferencer what is and is not allowed. So when you write foo(A) -> A. all the type inferencer can come up with for the signature of foo/1 is ANY -> ANY (where ANY is the set of all types.) But if you add a guard to foo/1 like so: foo(A) when is_integer(A) -> A. suddenly the type inferencer knows foo/1 is INTEGER -> INTEGER. And in some other place in the file, if you call foo(bar), it will complain, at compile time, that the sets ATOM and INTEGER are disjunct, you silly, fallible human, you. This could also open the door for user-defined guards - because it can check that guard expressions are indeed side-effectless and constant-time, and disallow them (or refactor them) if they aren't. My 2 Zorkmids for this morning, -Chris From cpressey@REDACTED Fri Sep 19 19:35:27 2003 From: cpressey@REDACTED (Chris Pressey) Date: Fri, 19 Sep 2003 10:35:27 -0700 Subject: Enhanced type guard syntax] In-Reply-To: <20030918215106.GA12828@bluetail.com> References: <20030918080921.3ebe542e.cpressey@catseye.mine.nu> <20030918215106.GA12828@bluetail.com> Message-ID: <20030919103527.23f672e9.cpressey@catseye.mine.nu> On Thu, 18 Sep 2003 23:51:07 +0200 Klacke wrote: > On Thu, Sep 18, 2003 at 08:09:21AM -0700, Chris Pressey wrote: > > > I think you CAN throw "when" completely away IF you take this new > > syntax proposal to its logical extreme. > > > > foo(X, Y) when X == 2*Y > > > > becomes > > > > foo(X == 2 * Y) > > > > > Bad, uncomprehensible. > > I don't see the point in this new propasal at all. Brilliantly argued, sir! :) To clarify my position: I submit that foo(X > Y) -> contains the exact same amount of information as foo(X, Y) when X > Y -> while being more concise. I also don't think it's any more difficult to read, once you unlearn the arbitrary convention that "comma seperates arguments". (Not that I'm proposing it for Erlang, since such a huge change would be lethal to backwards-compatibility. But as a language design idea in its own right, I like it.) -Chris From mlogan@REDACTED Fri Sep 19 22:53:06 2003 From: mlogan@REDACTED (Martin J. Logan) Date: 19 Sep 2003 15:53:06 -0500 Subject: Enhanced type guard syntax] In-Reply-To: <20030918152441.2b2d7037.cpressey@catseye.mine.nu> References: <3F697CCB.6000603@erix.ericsson.se> <3F69955D.2000806@futuresource.com> <001701c37dde$6d782d30$a22d1081@ituniv398> <3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> Message-ID: <1064004785.2708.1179.camel@dhcp-lom-194-186.futuresource.com> On Thu, 2003-09-18 at 17:24, Chris Pressey wrote: > On Thu, 18 Sep 2003 22:02:26 +0200 > Joachim Durchholz wrote: > > > Thomas Arts wrote: > > > [...] there was a philosophy that all guards should be executable in > > > constant time. > > > > This philosophy doesn't work out IMHO. > > Either, the guard is used as a selector. Then, if the guard is > > disallowed, people are going to write the exactly same > > non-constant-time code into the condition of an "if" statement, and > > nothing is won. Or the guard is used as a precondition. In that case, > > it shouldn't be a guard (but an assert statement or something - > > particularly, something that can be switched off for production code). > > > > Just my 2c. > > > > Regards, > > Jo > > Sing it, brother! > > A much nicer world would be: > > 1) the programmer writes whatever code they want in the "when" test > 2) the compiler analyzes that code > 3) whatever parts of it that have side-effects are rejected How could this be done at compile time while still using run time function call binding? If I say erlc modfoo.erl and it uses a guard that references code in modbar.erl erlc must be made aware of modbar.erl so it can look for a "!" in that module. > 4) whatever parts of it are constant-time are used as the guard > 5) whatever parts of it are non-constant-time are factored out into a > "case" statement > > But that sort of requires that a) compiler-writers are well paid and b) > the language is optimized for maintainability over efficiency... which > only ever seem to hold true in my private little world. > > -Chris From sean.hinde@REDACTED Sat Sep 20 00:46:54 2003 From: sean.hinde@REDACTED (Sean Hinde) Date: Fri, 19 Sep 2003 23:46:54 +0100 Subject: OS X patch for run_erl.c In-Reply-To: <3F657325.3070702@ericsson.com> Message-ID: <2AC2F4BA-EAF3-11D7-8EDB-000A95927CCE@mac.com> On Monday, September 15, 2003, at 09:07 am, Bengt Kleberg wrote: > Sean Hinde wrote: >> Hi, >> The following patch to run_erl.c is required for Erlang to run in >> embedded mode under OS X. Without this patch run_erl fails to create >> the > > ...deleted >> +#ifdef HAVE_MACH_O_DYLD_H >> + if ((mkfifo(name, perm) < 0) && (errno != EEXIST)) >> +#else >> + if ((mknod(name, S_IFIFO | perm, 0) < 0) && (errno != EEXIST)) >> +#endif > > perhaps mkfifo() is deprecated (or something even worse :-), but would > it not have been better to test like this: > > #ifdef HAVE_MKFIFO > if ((mkfifo(name, perm) < 0) && (errno != EEXIST)) > #else > if ((mknod(name, S_IFIFO | perm, 0) < 0) && (errno != EEXIST)) > #endif > No doubt. I leave it to the real maintainers of Erlang to take care of elegance in the build process. All this difficult cross platform C stuff is light years from anything I claim competence in, beyond the annoying necessity to occasionally waste many hours making Erlang work on my favourite laptop :) Sean From vances@REDACTED Sat Sep 20 03:26:01 2003 From: vances@REDACTED (Vance Shipley) Date: Fri, 19 Sep 2003 21:26:01 -0400 Subject: monitor message order Message-ID: <20030920012601.GH25374@frogman.motivity.ca> If I have a process set up multiple monitors to another process is there any telling which monitor reference will be returned first? FIFO? FILO? Random? I'm trying to keep track of the processes that have created resources on a server and garbage collect those resources when the process goes away without cleaning up after itself. It's easy enough at first glance but I'm struggling with the order of operations as there are dependencies on these resources. If I could be sure of the order of receipt of the 'DOWN' messages it would greatly simplify things. -Vance From cpressey@REDACTED Sat Sep 20 21:25:44 2003 From: cpressey@REDACTED (Chris Pressey) Date: Sat, 20 Sep 2003 12:25:44 -0700 Subject: Enhanced type guard syntax] In-Reply-To: <1064004785.2708.1179.camel@dhcp-lom-194-186.futuresource.com> References: <3F697CCB.6000603@erix.ericsson.se> <3F69955D.2000806@futuresource.com> <001701c37dde$6d782d30$a22d1081@ituniv398> <3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> <1064004785.2708.1179.camel@dhcp-lom-194-186.futuresource.com> Message-ID: <20030920122544.753bae14.cpressey@catseye.mine.nu> On 19 Sep 2003 15:53:06 -0500 "Martin J. Logan" wrote: > On Thu, 2003-09-18 at 17:24, Chris Pressey wrote: > > A much nicer world would be: > > > > 1) the programmer writes whatever code they want in the "when" test > > 2) the compiler analyzes that code > > 3) whatever parts of it that have side-effects are rejected > > How could this be done at compile time while still using run time > function call binding? > If I say erlc modfoo.erl and it uses a guard that references code in > modbar.erl erlc must be made aware of modbar.erl so it can look for a > "!" in that module. Well I never said it would be easy :) The really tricky part is when modbar.erl undergoes hot code upgrade. But even if the functions in a guard were restricted to the current module, I think it'd be a win for expressivity. -Chris From vlad_dumitrescu@REDACTED Sat Sep 20 21:50:22 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Sat, 20 Sep 2003 21:50:22 +0200 Subject: calling C code // drivers Message-ID: Hi, I sat and daydreamed today, and I have a few questions that I hope someone will be kind enough to answer... Are there any specific reasons to use the current way of interfacing with C code (i.e. the drivers) as it is today opposed to another one? What are the arguments for not using a more direct way than today? What I have in mind is the fact that with Hipe Erlang functions are compiled to native code - in theory, I can't see any reason why one couldn't compile C code to look like Hipe generated one. Thus we could have everybody write their own BIFs!! :-) In any case, it would be easier to interfacce with external libraries (and also the result might be a little faster?) Is this possible at all, or am I unaware of issues that forbid it? regards, Vlad From Erik.Stenman@REDACTED Sat Sep 20 22:15:46 2003 From: Erik.Stenman@REDACTED (Erik Stenman) Date: Sat, 20 Sep 2003 22:15:46 +0200 Subject: calling C code // drivers In-Reply-To: Message-ID: > Hi, > > I sat and daydreamed today, and I have a few questions that I > hope someone will be kind enough to answer... > > Are there any specific reasons to use the current way of > interfacing with C code (i.e. the drivers) as it is today > opposed to another one? What are the arguments for not using > a more direct way than today? What I have in mind is the fact > that with Hipe Erlang functions are compiled to native code - > in theory, I can't see any reason why one couldn't compile C > code to look like Hipe generated one. Thus we could have > everybody write their own BIFs!! :-) In any case, it would be > easier to interfacce with external libraries (and also the > result might be a little faster?) > > Is this possible at all, or am I unaware of issues that forbid it? Well, it is definitely possible, but I would advice against it, for at least these two reasons: 1. As the system is structured today there is only one emulator thread running. This means that when a BIF is called all other Erlang processes are blocked. Hence, BIFs are *not allowed* to take a long time to execute. If you make a mistake or deadlock in the BIF everything blocks. 2. There is no marshalling when calling BIFs. That means that the BIFs have to deal directly with tagged Erlang values, and interact with the GC and so on. Again if you make a mistake here the whole system will crash, and often in very unpredictable ways. (Believe me, GC bug are not easy to find, even though the hunt might be fun in a masochistic sort of way. ;) For interfacing C, it is much safer to put your C-interface in a separate driver (or even better in a separate process and talk to it through a socket). For efficiency, if you have a really, really time critical function which does not take a long time to execute ;) and it is simple to implement so you can be sure no mistakes are made, and no memory needs to be allocated then, maybe, maybe you could write your own BIF and link it into the system. But in that case you would probably be better off writing the function in Erlang and native code compiling it with HiPE. Erik - HiPE Hacker. -------------- next part -------------- A non-text attachment was scrubbed... Name: winmail.dat Type: application/ms-tnef Size: 3164 bytes Desc: not available URL: From hakan.stenholm@REDACTED Sat Sep 20 23:25:12 2003 From: hakan.stenholm@REDACTED (=?ISO-8859-1?Q?H=E5kan_Stenholm?=) Date: Sat, 20 Sep 2003 23:25:12 +0200 Subject: calling C code // drivers In-Reply-To: Message-ID: On l?rdag, sep 20, 2003, at 21:50 Europe/Stockholm, Vlad Dumitrescu wrote: > Hi, > > I sat and daydreamed today, and I have a few questions that I hope > someone > will be kind enough to answer... > > Are there any specific reasons to use the current way of interfacing > with C > code (i.e. the drivers) as it is today opposed to another one? What > are the > arguments for not using a more direct way than today? What I have in > mind is > the fact that with Hipe Erlang functions are compiled to native code - > in > theory, I can't see any reason why one couldn't compile C code to look > like > Hipe generated one. Hipe only works on certain OS/CPU combinations (Linux/Intel and Solaris/Sparc) so a number of currently supported platforms (Windows/Intel, MacOSX/PPC, Linux/PPC, ...) couldn't handle interfacing to C this way. > Thus we could have everybody write their own BIFs!! :-) > In any case, it would be easier to interfacce with external libraries > (and > also the result might be a little faster?) > > Is this possible at all, or am I unaware of issues that forbid it? > > regards, > Vlad > > > From luke@REDACTED Sat Sep 20 11:25:03 2003 From: luke@REDACTED (Luke Gorrie) Date: 20 Sep 2003 11:25:03 +0200 Subject: YATT (Yet Another Typing Thread) In-Reply-To: <018701c37e9f$b789ff40$a22d1081@ituniv398> References: <3F697CCB.6000603@erix.ericsson.se> <3F69955D.2000806@futuresource.com> <001701c37dde$6d782d30$a22d1081@ituniv398> <3F6A0F52.8050408@web.de> <20030918152441.2b2d7037.cpressey@catseye.mine.nu> <00a901c37e81$c4bff020$a22d1081@ituniv398> <3F6ABEC7.3090903@manderp.freeserve.co.uk> <3F6AC70A.3040609@manderp.freeserve.co.uk> <3F6ADA5B.6090604@manderp.freeserve.co.uk> <018701c37e9f$b789ff40$a22d1081@ituniv398> Message-ID: Hello, This is probably a bad time to start a different thread about typing in Erlang. But I'm doing it anyway :-). In my playing around I have found a nice type system, and would like to put it on the radar of Erlang hackers and hear what people doing static-typing for Erlang think of it. I refer to CMU Common Lisp (CMUCL). This is a free Lisp system that has been actively developed since early in the 1980s and continues today. http://www.cons.org/cmucl/ They have a very interesting approach to typing which is both static and dynamic. They don't make the language fully statically typed, but instead do as much as possible with what type information they have available. The type information available in a Common Lisp program is very similar to what's available in an Erlang program, mostly from type-checking guards. This makes me think the CMUCL approach may work well for Erlang too. CMUCL is interesting because they do a _lot_ with the type information available. For example: * Compiler optimizations. e.g. if some variables are declared to be floats, you can generate more efficient code for doing arithmetic on them. Erlang/BEAM does this too - that's why there are so many 'float(X)' type declarations in the Wings3D code that Ulf quoted (excerpted down below). This is safe because before the float-specific code is executed the arguments are runtime-checked to actually be floats -- like in Erlang, type guards/declarations are not blindly trusted, they are treated as assertions to be checked. * Type inference. If some variables have specified types, this is used to figure out the types of more variables. For example, with: foo(X, Y) when float(X) -> Z = X * Y, ... You can figure out that Z is also a float. You also know that Y has to be a number in any of the "..." code, because otherwise it would have crashed with badarg on the the first line before getting that far. * Efficiency notes. If you want a function to be fast, you can tell the compiler so. It will then report every optimization opportunity that was missed because of insufficient type information. Take the Wings3d example again: they have added float(X) declarations in strategic places to generate fast code. Exactly which declarations they add are, I believe, based on deep knowledge of the compiler and BEAM. In CMUCL it is easier for mortals. You write the function with no type declarations, and say "this has to be fast". Then the compiler will print notes to the effect that "Hey, I could generate faster code if I knew that X, Y, and Z were floats". Then, if you know that they really should be floats, you add the type guards and get the good code. Thus you can do effective low-level optimization without intimate knowledge of the compiler. * Conservative static type error detection. If the compiler sees that you will cause a type error, it will give you a warning. It does this when it can prove that your code _will_ lead to a type error, not just that it might. For example, this code would generate a warning: X + length(X) because it could never work correctly: X has to be both a list and an integer, which is impossible. Note that it's a warning and not an error: maybe you want to test some other parts of the program before you fix this. Overall you get a lot of benefits and none of the drawbacks usually associated (by us Erlang programmers at least) with static typing - i.e. it makes no restrictions on how you write code and you can ignore the warnings if you want. In practice you do not ignore the warnings, because the compiler only bothers to warn you when you've almost certainly made a mistake. So what does this mean to us Erlang programmers? Is this something we'd like? Are recent compiler/BEAM developments already leading us in this direction? Are there some fundamental reasons that this would not work as well for Erlang that the type-theorists can tell us? Should I shut the hell up about Lisp already? :-) In any case, there are worse ways to spend a lazy afternoon than reading the CMU Common Lisp user manual -- particularly the section on advanced compiler usage. It is a seriously excellent work of programming language implementation, even if you aren't interested in Lisp per se. The URL is: http://www.cons.org/cmucl/doc/index.html Also -- I don't like playing the luddite, but I never understand conference talks about type systems. I'm not familiar with the formalism(s) that people use and just see a lot of greek letters. Can someone explain what formalisms people are using (e.g. is it declarative semantics, or..?), and perhaps point to a book or two that one could read to appreciate what's going on? Here's the Wings3D code that Ulf quoted: twist_fun(y, {Cx,_,Cz}) -> fun(U, Min, {X0,Y,Z0}) when float(U), float(Min), float(X0), float(Y), float(Z0) -> Angle = U*(Y-Min), Cos = math:cos(Angle), Sin = math:sin(Angle), X = X0 - Cx, Z = Z0 - Cz, {X*Cos+Z*Sin+Cx,Y,Z*Cos-X*Sin+Cz} end; (BTW, comparison to CL also suggests another possible notation for writing type guards: "when float(U, Min, X0, Y, Z0) ->", i.e. to make the type guards n-ary.) Cheers, Luke From valentin@REDACTED Sun Sep 21 11:26:20 2003 From: valentin@REDACTED (Valentin) Date: Sun, 21 Sep 2003 11:26:20 +0200 Subject: calling C code // drivers References: Message-ID: <001601c38022$7277c0c0$01010d0a@moneymaker> Erik wrote: >For interfacing C, it is much safer to put your C-interface in >a separate driver (or even better in a separate process and talk >to it through a socket). I cannot agree more, however, even this is not always safe -- recently we managed to crash Erlang by simply passing an invalid argument in RPC call... to cut the story short, by passing a pointer to the prevously deallocated (hence dirty) memory, Erlang runtime received TERM which size exceeded the allocated memeory. Now, I would much rather have a caller crashing during the encoding/marshalling (ei_encodexxx(...)), however, due to the specific memory handling of the host operating system (Solaris never stops to amaze me), the calling process memory overrun was tolerated, but ERTS wasn't as forgiving. Valentin. From vlad_dumitrescu@REDACTED Sun Sep 21 15:13:52 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Sun, 21 Sep 2003 15:13:52 +0200 Subject: list handling functions References: <20030919.155655.74729923.svg@surnet.ru> Message-ID: Thanks for the hints, Richard and Vladimir. And for the code, of course. I had defined for example map2, map3.. map5, but using a list of lists as argument is much better. regards, Vlad From vlad_dumitrescu@REDACTED Sun Sep 21 15:19:28 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Sun, 21 Sep 2003 15:19:28 +0200 Subject: calling C code // drivers References: Message-ID: From: "H?kan Stenholm" >Hipe only works on certain OS/CPU combinations (Linux/Intel and >Solaris/Sparc) so a number of currently supported platforms >(Windows/Intel, MacOSX/PPC, Linux/PPC, ...) couldn't handle interfacing >to C this way. Yes, this is true - for the time being. I don't think there is a fundamental problem that restricts the number of usable platforms, so it's just a matter of resources and interest. /Vlad From svg@REDACTED Sun Sep 21 16:48:42 2003 From: svg@REDACTED (Vladimir Sekissov) Date: Sun, 21 Sep 2003 20:48:42 +0600 (YEKST) Subject: monitor message order In-Reply-To: <20030920012601.GH25374@frogman.motivity.ca> References: <20030920012601.GH25374@frogman.motivity.ca> Message-ID: <20030921.204842.78727768.svg@surnet.ru> Good day, vances> If I have a process set up multiple monitors to another vances> process is there any telling which monitor reference will vances> be returned first? FIFO? FILO? Random? If I correctly understand source erts/emulator/beam/erl_process.c erts/emulator/beam/bif.c erts/emulator/beam/utils.c the order is LIFO. Reference consists from four cyclic counters so we can do simple test: 19> F1 = fun () -> receive stop -> exit(normal) end end. #Fun 24> F2 = fun (Cont) -> receive Msg -> io:format("~p~n", [Msg]), Cont(Cont) after 5000 -> ok end end. #Fun 25> F3 = fun (Pid) -> lists:foreach(fun (_) -> erlang:monitor(process, Pid) end, [1,2,3,4,5,6]), Pid ! stop, F2(F2) end. 27> F3(spawn(F1)). {'DOWN',#Ref<0.0.0.11860>,process,<0.2289.0>,normal} {'DOWN',#Ref<0.0.0.11859>,process,<0.2289.0>,normal} {'DOWN',#Ref<0.0.0.11858>,process,<0.2289.0>,normal} {'DOWN',#Ref<0.0.0.11857>,process,<0.2289.0>,normal} {'DOWN',#Ref<0.0.0.11856>,process,<0.2289.0>,normal} {'DOWN',#Ref<0.0.0.11855>,process,<0.2289.0>,normal} ok Best Regards, Vladimir Sekissov vances> vances> If I have a process set up multiple monitors to another vances> process is there any telling which monitor reference will vances> be returned first? FIFO? FILO? Random? vances> vances> I'm trying to keep track of the processes that have created vances> resources on a server and garbage collect those resources vances> when the process goes away without cleaning up after itself. vances> vances> It's easy enough at first glance but I'm struggling with the vances> order of operations as there are dependencies on these vances> resources. If I could be sure of the order of receipt of vances> the 'DOWN' messages it would greatly simplify things. vances> vances> -Vance From alexey@REDACTED Sun Sep 21 21:26:20 2003 From: alexey@REDACTED (Alexey Shchepin) Date: Sun, 21 Sep 2003 22:26:20 +0300 Subject: OTP application example Message-ID: <87fziq54f7.fsf@alex.sevcom.net> Hi! Is there exists an open-source Erlang application that can be used as example of OTP principles usage? I.e. that have at least install and upgrade scripts that uses release_handler. From cpressey@REDACTED Sun Sep 21 23:32:52 2003 From: cpressey@REDACTED (Chris Pressey) Date: Sun, 21 Sep 2003 14:32:52 -0700 Subject: package syntax patch for syntax_tools Message-ID: <20030921143252.5efa5ec1.cpressey@catseye.mine.nu> Hi all, One of the major drawbacks to the package system I've found so far is that the latest available version of syntax_tools doesn't seem to understand it... I translated all of openflax to use the package system only to find that edoc chokes on it :( Luckily, syntax_tools is well commented, so it wasn't hard to hack it to allow for dotted atoms and -import(module). But the patches (attached) are just that - a hack so that edoc doesn't choke. Hopefully Richard will craft something more elegant for the next release of syntax_tools & edoc, pending the fate of packages. In the meantime, shall I throw these patches into the Jungerl? -Chris -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: erl_syntax.patch URL: -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: erl_syntax_lib.patch URL: From hakan.stenholm@REDACTED Mon Sep 22 01:47:05 2003 From: hakan.stenholm@REDACTED (=?ISO-8859-1?Q?H=E5kan_Stenholm?=) Date: Mon, 22 Sep 2003 01:47:05 +0200 Subject: calling C code // drivers In-Reply-To: Message-ID: On s?ndag, sep 21, 2003, at 15:19 Europe/Stockholm, Vlad Dumitrescu wrote: > From: "H?kan Stenholm" >> Hipe only works on certain OS/CPU combinations (Linux/Intel and >> Solaris/Sparc) so a number of currently supported platforms >> (Windows/Intel, MacOSX/PPC, Linux/PPC, ...) couldn't handle >> interfacing >> to C this way. > > Yes, this is true - for the time being. I don't think there is a > fundamental > problem that restricts the number of usable platforms, so it's just a > matter > of resources and interest. > Your quite right that there are probably no real fundamental reasons why this wouldn't work. Erik mentioned a number of more fundamental safety reasons why this might be a bad idea. I mainly wanted to point out that this solution, isn't currently practical as a driver replacement for all platforms, and considering the time currently needed to implement HIPE for a CPU architecture, will most likely mean that there will always be some platforms that aren't supported - so it may be hard to get rid of the current driver implementation. This would also make Erlang less portable, as things like user defined BIFs would only work on some platforms (the ones that support HIPE). > /Vlad > From fritchie@REDACTED Mon Sep 22 06:44:26 2003 From: fritchie@REDACTED (Scott Lystig Fritchie) Date: Sun, 21 Sep 2003 23:44:26 -0500 Subject: calling C code // drivers In-Reply-To: Message of "Sat, 20 Sep 2003 21:50:22 +0200." Message-ID: <200309220444.h8M4iQTk026590@snookles.snookles.com> >>>>> "vd" == Vlad Dumitrescu writes: vd> Thus we could have everybody write their own BIFs!! vd> :-) In any case, it would be easier to interfacce with external vd> libraries (and also the result might be a little faster?) An issue not mentioned in this thread yet is single-assignment. If exyour C is using pointers/pass-by-reference to meddle with the caller's data, you're almost always in trouble. (If the VM has never seen the caller's data, then you're OK. But that isn't a very fun or useful or real-world case.) -Scott P.S. One of the things that I've always wanted to do with my pet project, Erlang Driver ToolKit (http://www.snookles.com/erlang/edtk/), is to make it possible for drivers to access the raw Erlang tagged term data. The formalism for passing serialized data into the driver is nearly sufficient for the task. But it doesn't solve the "one bug and your VM is toast" problem. These Erlang people -- they're *so* fault-conscious. :-) From fritchie@REDACTED Mon Sep 22 07:06:29 2003 From: fritchie@REDACTED (Scott Lystig Fritchie) Date: Mon, 22 Sep 2003 00:06:29 -0500 Subject: BEAM documentation (was Re: Packages in Erlang...) In-Reply-To: Message of "15 Sep 2003 15:16:31 +0200." Message-ID: <200309220506.h8M56TTk026849@snookles.snookles.com> >>>>> "lg" == Luke Gorrie writes: lg> Aside from the BIFs, another issue is linked in drivers. Do you lg> know how separable those are? In practice do you need to link some lg> of them with BEAM'ey libraries or similar? I faced that problem with EDTK's design goal to support both linked-in and pipe drivers. The source file edtk/erl_driver_pipelib.c contains the functions that EDTK-generated drivers need. This list is a first draft of an upper limit on the functions a linked-in driver needs. (A bad, bad one could try calling just about anything inside BEAM using dlsym(). :-) Some of them aren't necessary, depending on the communcation style the driver uses. (Corollary: if you used a different communcation style (there are several to choose from!), you might need others.) ErlIOVec *read_packet_make_iovec(int fd) ErlDrvBinary *driver_alloc_binary(int size) ErlDrvBinary *driver_realloc_binary(ErlDrvBinary *oldbin, int size) void driver_free_binary(ErlDrvBinary *ebin) void *sys_alloc(size_t size) void sys_free(void *p) int driver_output_term(ErlDrvPort ix, ErlDrvTermData* data, int len) long driver_async(ErlDrvPort ix, unsigned int* key, void (*async_invoke)(void*), void* async_data, void (*async_free)(void*)) ErlDrvTermData driver_mk_atom(char *name) ErlDrvTermData driver_mk_port(ErlDrvPort port) int driver_select(ErlDrvPort port, ErlDrvEvent event, int mode, int on) At the time, I was happy it was a small list. -Scott From ok@REDACTED Mon Sep 22 07:18:08 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Mon, 22 Sep 2003 17:18:08 +1200 (NZST) Subject: Enhanced type guard syntax] Message-ID: <200309220518.h8M5I8dv008990@atlas.otago.ac.nz> Joe Armstrong wrote: It depends upon the set of patterns. If we have a polymorphic function like this: foo(A/integer, B/...) -> foo(A/integer, B/...) foo(true, ...) -> foo(bar, ...) -> Then any half decent pattern matching compiler could generate pattern matching code like this.... switchOnTag Arg0 { case integer: ... case atom: ... } But any half-way decent pattern-matching compiler *should* be generating pattern-matching code like that anyway for foo(A, B) when integer(A), ... -> foo(A, B) when integer(A), ... -> foo(true, ...) when ... -> foo(bar, ...) when ... -> Someone under Udi Shapiro's supervision wrote a compiler for FCP that did that years back. I *think* the name was Shmuel Kliger, but I am probably wrong, and I *think* the year I read it was 1990, but ditto. And of course I may be misremembering it. Basic ideas: (1) Compile pattern matches and guards together (2) Do guard tests when the data are known to be available (for Prolog, a variable may be tested after the _last_ mention of it in a pattern; for Erlang it may be tested after the _first_ mention). So integer(A) may be scheduled at any point after the first mention of A in the head, A > B may be done at any point after A and B both become available, and so on. (3) Introduce the generalisations of a test: integer(A) => atomic(A) & number(A) & integer(A) A = 27 => integer(A).... & A = 27 A = true => atomic(A) & atom(A) & A = true hd(X) > 2 => is_pair(X) & [H|_] = X & atomic(H) & number(H) & H > 2 ... (4) If a test is implied by tests you have already done, emit no code for it. (5) When building the tree, at each node pick the most useful test. I've forgotten the exact rule, but it's something about filtering out the largest number of clauses, and something about expense. My general feeling is that "the more you tell the compiler about the program the better" As a programmer you shouldn't think about how to write patterns, or guards for efficiency - let the pattern matching compiler do that. Right. If Erlang _were_ to be extended with IBM-PROLOG-like type tests in patterns (*YUCK*) then it should make absolutely no difference to the compiler whether you do it that way or not. From ok@REDACTED Mon Sep 22 07:21:40 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Mon, 22 Sep 2003 17:21:40 +1200 (NZST) Subject: Use-defined guard (was: RE: Enhanced type guard syntax]) Message-ID: <200309220521.h8M5LeJi478902@atlas.otago.ac.nz> "Fredrik Linder" However, by allowing only a limited set of operations in guard-declared functions (such as only allowing then to call other guard-functions) could be the fine line that increases usability while still preserving the consistency of the program. The usage I am targeting is to have user-defined guards as inspectors/selectors on ADTs. Except for the unnecessarily ugly syntax and not being quite as fully worked out, how is this different from my old "Abstract Patterns" proposal? From ok@REDACTED Mon Sep 22 07:38:20 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Mon, 22 Sep 2003 17:38:20 +1200 (NZST) Subject: Enhanced type guard syntax] Message-ID: <200309220538.h8M5cKYg419158@atlas.otago.ac.nz> Ulf_Wiger wrote: The following code snippet from wings_deform.erl: twist_fun(y, {Cx,_,Cz}) -> fun(U, Min, {X0,Y,Z0}) when float(U), float(Min), float(X0), float(Y), float(Z0) -> Angle = U*(Y-Min), Cos = math:cos(Angle), Sin = math:sin(Angle), X = X0 - Cx, Z = Z0 - Cz, {X*Cos+Z*Sin+Cx,Y,Z*Cos-X*Sin+Cz} end; I have to ask "what are those float/1 tests doing there at all?" Surely the normal use of guards is to select between alternatives? There is no alternative here. All that these guards are doing is turning _meaningful_ calls (like F(0,0,{0,0,0}) into errors. What _would_ be useful from an error-detection point of view would be to check that Cx and Cz are numbers, but that is _not_ done. Surely the best way to simplify that code is twist_fun(y, {Cx,_,Cz}) -> % maybe check Cx, Cz are numbers before it's too late? fun(U, Min, {X0,Y,Z0}) -> Angle = U*(Y-Min), Cos = math:cos(Angle), Sin = math:sin(Angle), X = X0 - Cx, Z = Z0 - Cz, {X*Cos+Z*Sin+Cx,Y,Z*Cos-X*Sin+Cz} end; In this particular code (I believe), type guards are important from a performance perspective, since floating point operations are performed more efficiently if the compiler can _know_ that the input parameters are really floats. It's not clear to me that tweaking performance in very minor ways at the price of turning meaningful calls into errors is a good way for Erlang to go. Note that with the original code the compiler does NOT know that Cx and Cz are floats (or even that they are numbers) so that the last three lines of calculations have to be done in a general way anyway, and that the cost is likely to be dominated by the calls to math:cos/1 and math:sin/1. Is there a way you can get the speed benefit of knowing that something is a float _without_ going out of your way to lock out meaningful calls and _without_ any language changes? Yes: twist_fun(y, {Cx,_,Cz}) -> Cxf = float(Cx), % check numeric & convert now Czf = float(Cz), % check numeric & convert now fun(U, Min, {X0,Y,Z0}) -> Angle = float(U)*(float(Y) - float(Min)), Cos = math:cos(Angle), Sin = math:sin(Angle), X = float(X0) - Cxf, Z = float(Z0) - Czf, {X*Cos+Z*Sin+Cxf, Y, Z*Cos-X*Sin+Czf} end; Now the compiler does know what is going on, _and_ other numeric types can be passed in. There's no extra cost for arguments that _are_ floats, because the check had to be done anyway. Also, it's consistent with the bit syntax, so the X/Type syntax has already been added to the language. I hadn't really regarded those things as types but as formats; possibly because I thought of them as related to Perl's "pack" and "unpack". From ok@REDACTED Mon Sep 22 08:13:08 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Mon, 22 Sep 2003 18:13:08 +1200 (NZST) Subject: Enhanced type guard syntax] Message-ID: <200309220613.h8M6D8np012079@atlas.otago.ac.nz> Concerning the examples: foo(X == 2 * Y) % foo(X, Y) when X == 2*Y foo(X > Y) % foo(X, Y) when X > Y am I the only one who is bothered (to put it politely) that the "improved" versions _look_ as if they have one argument, but are supposedly equivalent to functions with _two_ arguments, and that there's no obvious way to tell which argument is which? For some reason, Haskell programmers don't seem to might writing foo x y | x == 2*y = ... foo x y | x < y = ... "Chris" wrote: I also don't think it's any more difficult to read, once you unlearn the arbitrary convention that "comma seperates arguments". It may be arbitrary, but so are all human communication conventions, and this one has been going strong in programming languages for 50 years. "As a language design idea in its own right", I very much dislike a notation where I can't tell which argument is which. Now let's consider f([X|_], [Y|_]) when X < Y -> ... how do you write _that_ without commas? Good ideas (like abstract patterns) work in general cases. From erlang@REDACTED Mon Sep 22 09:29:05 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Mon, 22 Sep 2003 08:29:05 +0100 Subject: Enhanced type guard syntax] In-Reply-To: <200309220613.h8M6D8np012079@atlas.otago.ac.nz> References: <200309220613.h8M6D8np012079@atlas.otago.ac.nz> Message-ID: <3F6EA4C1.7010906@manderp.freeserve.co.uk> Hi Gurus, After spending a weekend thinking about totally unrelated things, and now that my mind is somewhat refreshed, my opinion is _NO_, please don't change the notation. The only "gain" is a change in syntax. I'm perfectly happy to read the "English" version. As for optimisation, where I've needed high speed bit-crunching I've resorted to C and C-node servers. This kinda dodges the language-improvement issue, but I'm simply being pragmatic, and it has worked very well for what I've done. Speed in Erlang isn't a big issue for me. As for type-checking and code-correctness a code analyser would be a wonderfully powerful design tool. Erlang already has the remarkable quality of expressing algorithms clearly. I make lots of syntactic errors when writing (wither semicolon?), but once I've cleaned them up, most of the time the code semantics are correct and works as desired. Yay! But in practice I've rarely had such obscure problems as "how did an atom end up being used as a number?". Maybe the excellent error trapping and recovery mechanisms in Erlang could be to "blame" for this? I found debugging Erlang code is relatively easy, because the error reports are exact and meaningful, and the programs don't go quietly mad before failing miles down the execution path. Pete. Richard A. O'Keefe wrote: > Concerning the examples: > > foo(X == 2 * Y) > % foo(X, Y) when X == 2*Y > foo(X > Y) > % foo(X, Y) when X > Y > > am I the only one who is bothered (to put it politely) that the > "improved" versions _look_ as if they have one argument, but are > supposedly equivalent to functions with _two_ arguments, and that > there's no obvious way to tell which argument is which? > > For some reason, Haskell programmers don't seem to might writing > > foo x y | x == 2*y = > ... > foo x y | x < y = > ... > > "Chris" wrote: > > I also don't think it's any more difficult to read, once you > unlearn the arbitrary convention that "comma seperates arguments". > > It may be arbitrary, but so are all human communication conventions, > and this one has been going strong in programming languages for 50 years. > "As a language design idea in its own right", I very much dislike a > notation where I can't tell which argument is which. > > Now let's consider > > f([X|_], [Y|_]) when X < Y -> ... > > how do you write _that_ without commas? Good ideas (like abstract patterns) > work in general cases. > > > From sean.hinde@REDACTED Mon Sep 22 10:40:46 2003 From: sean.hinde@REDACTED (Sean Hinde) Date: Mon, 22 Sep 2003 09:40:46 +0100 Subject: Use-defined guard (was: RE: Enhanced type guard syntax]) In-Reply-To: <200309220521.h8M5LeJi478902@atlas.otago.ac.nz> Message-ID: <75C3528A-ECD8-11D7-8EDB-000A95927CCE@mac.com> On Monday, September 22, 2003, at 06:21 am, Richard A. O'Keefe wrote: > "Fredrik Linder" However, by allowing > only a limited set of operations in guard-declared > functions (such as only allowing then to call other guard-functions) > could > be the fine line that increases usability while still preserving the > consistency of the program. > > The usage I am targeting is to have user-defined guards as > inspectors/selectors on ADTs. > > Except for the unnecessarily ugly syntax and not being quite as fully > worked out, how is this different from my old "Abstract Patterns" > proposal? > > I can't seem to find this proposal online. Link anyone? Sean From luke@REDACTED Mon Sep 22 15:17:31 2003 From: luke@REDACTED (Luke Gorrie) Date: 22 Sep 2003 15:17:31 +0200 Subject: calling C code // drivers In-Reply-To: References: Message-ID: "Vlad Dumitrescu" writes: > Are there any specific reasons to use the current way of interfacing with C > code (i.e. the drivers) as it is today opposed to another one? What are the > arguments for not using a more direct way than today? What I have in mind is > the fact that with Hipe Erlang functions are compiled to native code - in > theory, I can't see any reason why one couldn't compile C code to look like > Hipe generated one. Thus we could have everybody write their own BIFs!! :-) CMUCL &co do this. You can just call any C function you like, even from the shell. You can also cast certain types of arrays/strings to C strings (char*) and so on. Thus they call select() etc directly from Lisp and don't have C drivers. Sounds nice. But there's a catch :-) I read about an _extremely_ nasty bug just the other day. It relates to a "write barrier" that their garbage collector uses. It uses the mprotect() system call to mark pages of memory as read-only, then a SIGSEGV handler to trap writes and allow them after recording the fact that the page was modified. This lets the garbage collector keep track of which objects have been modified since the last collection. Trouble was, Lisp strings are sometimes passed as char* buffers to system calls, and if that buffer's memory is read-only then the system call can't write to it -- the SIGSEGV handler is inhibited. So your reads will fail if the string you're using as a buffer has not been modified since the last garbage collection, because it's in read-only memory. This suggests to me that there's something to be said for doing all operating system interaction in a proper runtime system. :-) Certainly I'm glad the code I'm responsible is written in Erlang. Cheers, Luke (pretending not to be responsible for some nasty C code too..) From cpressey@REDACTED Mon Sep 22 16:54:58 2003 From: cpressey@REDACTED (Chris Pressey) Date: Mon, 22 Sep 2003 07:54:58 -0700 Subject: Enhanced type guard syntax] In-Reply-To: <200309220613.h8M6D8np012079@atlas.otago.ac.nz> References: <200309220613.h8M6D8np012079@atlas.otago.ac.nz> Message-ID: <20030922075458.64fc4ea3.cpressey@catseye.mine.nu> On Mon, 22 Sep 2003 18:13:08 +1200 (NZST) "Richard A. O'Keefe" wrote: > Concerning the examples: > > foo(X == 2 * Y) > % foo(X, Y) when X == 2*Y > foo(X > Y) > % foo(X, Y) when X > Y > > am I the only one who is bothered (to put it politely) that the > "improved" versions _look_ as if they have one argument, but are > supposedly equivalent to functions with _two_ arguments, and that > there's no obvious way to tell which argument is which? No, it also seemed to bother Klacke very much :) But what could be a more obvious way to tell which argument is which, than their order? in "X > Y", X appears first, so it's the first argument. > For some reason, Haskell programmers don't seem to might writing > > foo x y | x == 2*y = > ... > foo x y | x < y = > ... > > "Chris" wrote: > > I also don't think it's any more difficult to read, once you > unlearn the arbitrary convention that "comma seperates > arguments". > > It may be arbitrary, but so are all human communication conventions, > and this one has been going strong in programming languages for 50 > years."As a language design idea in its own right", I very much > dislike a notation where I can't tell which argument is which. Stick-in-the-mud! You're just jealous 'cuz I'm an "early adopter." :) Seriously, you have every right to dislike it as much or as little as you like since aesthetics are subjective and it's just another variation on notation. (That's probably the main reason people cringe at Forth and Lisp code too, it's "impossible to read" (until you learn to read it :)) But I don't think you can show that this notation is not more concise. Which, I believe, was the main thrust of the original thread (that A/integer is more concise than (A) when is_integer(A).) > Now let's consider > > f([X|_], [Y|_]) when X < Y -> ... > > how do you write _that_ without commas? You don't, because I didn't say "never use commas," I said "commas become 'and's" (or something very close to 'and') You write it like this: f([X | _], [Y | _], X < Y) -> -Chris From ulf.wiger@REDACTED Mon Sep 22 17:20:21 2003 From: ulf.wiger@REDACTED (=?iso-8859-1?Q?Ulf_Wiger_=28=C4L2/EAB=29?=) Date: Mon, 22 Sep 2003 17:20:21 +0200 Subject: bug in gs Message-ID: <76E5F712842F5F49A35738622BAA0F4F9EA736@ESEALNT442.al.sw.ericsson.se> I have the following rather obscure code using gs: cols(_) -> lists:duplicate(5,{stretch,1}). rows(_) -> lists:duplicate(7, {fixed,40}). widgets(_) -> window:buttons([{but_ok,"Ok"},{but_cancel,"Cancel"}], 1) ++ window:entries([{e_athlete_id, "Id"}, {e_athlete_number, "Number"}, {e_athlete_name, "Name"}, {e_athlete_born, "Born"}, {e_athlete_gender, "Gender"}, {e_athlete_club, "Club"}, {e_athlete_info, "Info"}], 2). window.erl: entries([{Name, Text}|Es], Row) -> [{label, [{label,{text,Text}}, {pack_xy,{1,Row}}]}, {entry, Name, [{pack_xy, {{2,4},Row}}]} | entries(Es, Row+1)]; entries([], _) -> []. The bug in the above code is that it declares 7 entries, each on a row + 1 button row, but (in rows/1) only 7 packer rows. This should not work, of course, but the error message (below) could be a bit more user-friendly: =ERROR REPORT==== 22-Sep-2003::17:05:29 === Error in process <0.263.0> with exit value: {function_clause,[{gstk_frame,find_pos,[8,8,8,150,0,[]]},{gstk_frame,pack_child,5},{gstk_frame,pack_children2,5},{gstk_frame,option,5},{gstk_generic,out_opts,8},{gstk_generic,make_command,7},{gstk_generic,mk_cmd_and_exec,... I suspect the logic in gstk_generic:gen_pack_xy/8 could be fixed to perform a sanity check and giving a better error description, but I'm too lazy to try to do it myself. /Uffe From svenolof@REDACTED Mon Sep 22 17:05:42 2003 From: svenolof@REDACTED (Sven-Olof Nystr|m) Date: Mon, 22 Sep 2003 17:05:42 +0200 Subject: Use-defined guard (was: RE: Enhanced type guard syntax]) In-Reply-To: <75C3528A-ECD8-11D7-8EDB-000A95927CCE@mac.com> References: <200309220521.h8M5LeJi478902@atlas.otago.ac.nz> <75C3528A-ECD8-11D7-8EDB-000A95927CCE@mac.com> Message-ID: <16239.4038.633847.469984@gargle.gargle.HOWL> Sean Hinde writes: > > On Monday, September 22, 2003, at 06:21 am, Richard A. O'Keefe wrote: > > Except for the unnecessarily ugly syntax and not being quite as fully > > worked out, how is this different from my old "Abstract Patterns" > > proposal? > I can't seem to find this proposal online. Link anyone? I have a copy. I could post it on the list, if Richard does not have any objections. Sven-Olof From csanto@REDACTED Mon Sep 22 18:32:44 2003 From: csanto@REDACTED (Corrado Santoro) Date: Mon, 22 Sep 2003 18:32:44 +0200 Subject: Problems in using http module Message-ID: <1064248364.3f6f242ccac18@www.cdc.unict.it> Hi all, I'm writing an http proxy server in Erlang, and I'm using the http module. First of all, I would highlight that the Erlang/OTP documentation seems to miss the needed infos on http module, it reports httpd, ftp, etc. but hot http. Secondly, I'm using the function http:request_sync to retrieve a web document but sometimes it fails reporting the "aborted_request" error. Does anyone know what does it mean? Third, Are there any problems in using the http module in a multi-processes program? Thank you for your help. Bye, -Corrado -- ====================================================== Eng. Corrado Santoro, Ph.D. University of Catania - Engineering Faculty Department of Computer Science and Telecommunications Engineering Viale A. Doria, 6 - 95125 CATANIA (ITALY) Tel: +39 095 7382364 Fax: +39 095 338280 EMail: csanto@REDACTED Personal Home Page: http://www.diit.unict.it/users/csanto NUXI Home Page: http://nuxi.iit.unict.it ====================================================== ------------------------------------------------- This mail sent through IMP: http://www.cdc.unict.it/ From vlad_dumitrescu@REDACTED Mon Sep 22 21:27:11 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Mon, 22 Sep 2003 21:27:11 +0200 Subject: new syntax - a provocation Message-ID: 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 From raimo@REDACTED Mon Sep 22 08:57:18 2003 From: raimo@REDACTED (Raimo Niskanen) Date: Mon, 22 Sep 2003 08:57:18 +0200 Subject: monitor message order References: <20030920012601.GH25374@frogman.motivity.ca>, <20030921.204842.78727768.svg@surnet.ru> Message-ID: Dont make yourself depending on the order - it may change in future releases if we happen to rewrite the code to gain a percent of speed, or something. / Raimo Niskanen, Erlang/OTP, Ericsson AB Vladimir Sekissov wrote: > Good day, > > vances> If I have a process set up multiple monitors to another > vances> process is there any telling which monitor reference will > vances> be returned first? FIFO? FILO? Random? > > If I correctly understand source > > erts/emulator/beam/erl_process.c > erts/emulator/beam/bif.c > erts/emulator/beam/utils.c > > the order is LIFO. > > Reference consists from four cyclic counters so we can do simple test: > > 19> F1 = fun () -> receive stop -> exit(normal) end end. > #Fun > > 24> F2 = fun (Cont) -> > receive > Msg -> > io:format("~p~n", [Msg]), Cont(Cont) > after 5000 -> ok > end > end. > #Fun > > 25> F3 = fun (Pid) -> > lists:foreach(fun (_) -> erlang:monitor(process, Pid) end, > [1,2,3,4,5,6]), > Pid ! stop, > F2(F2) > end. > 27> F3(spawn(F1)). > {'DOWN',#Ref<0.0.0.11860>,process,<0.2289.0>,normal} > {'DOWN',#Ref<0.0.0.11859>,process,<0.2289.0>,normal} > {'DOWN',#Ref<0.0.0.11858>,process,<0.2289.0>,normal} > {'DOWN',#Ref<0.0.0.11857>,process,<0.2289.0>,normal} > {'DOWN',#Ref<0.0.0.11856>,process,<0.2289.0>,normal} > {'DOWN',#Ref<0.0.0.11855>,process,<0.2289.0>,normal} > ok > > Best Regards, > Vladimir Sekissov > > vances> > vances> If I have a process set up multiple monitors to another > vances> process is there any telling which monitor reference will > vances> be returned first? FIFO? FILO? Random? > vances> > vances> I'm trying to keep track of the processes that have created > vances> resources on a server and garbage collect those resources > vances> when the process goes away without cleaning up after itself. > vances> > vances> It's easy enough at first glance but I'm struggling with the > vances> order of operations as there are dependencies on these > vances> resources. If I could be sure of the order of receipt of > vances> the 'DOWN' messages it would greatly simplify things. > vances> > vances> -Vance -- / Raimo Niskanen, Erlang/OTP, Ericsson AB From vances@REDACTED Mon Sep 22 22:48:32 2003 From: vances@REDACTED (Vance Shipley) Date: Mon, 22 Sep 2003 16:48:32 -0400 Subject: monitor message order In-Reply-To: References: <20030921.204842.78727768.svg@surnet.ru> Message-ID: <20030922204832.GQ25374@frogman.motivity.ca> I can accept that. It might be worth noting "order undefined" or something in the documentation. -Vance On Mon, Sep 22, 2003 at 08:57:18AM +0200, Raimo Niskanen wrote: } Dont make yourself depending on the order - it may change in future } releases if we happen to rewrite the code to gain a percent of speed, or } something. } } / Raimo Niskanen, Erlang/OTP, Ericsson AB From erlang@REDACTED Tue Sep 23 07:03:07 2003 From: erlang@REDACTED (erlang@REDACTED) Date: Tue, 23 Sep 2003 01:03:07 -0400 (EDT) Subject: new syntax - a provocation Message-ID: Along the lines of provocation, this suggests another thought: The one single source, as far as I can tell, of nonlinear algorithms in Erlang, is an inability to directly address list elements (as per array subscripts, or similar). I like lists. In fact, I love lists. But it seems to me that the current approach was rather one of using a pure linked list (or double linked list) for internal representation. (This is an educated guesstimate, and I invite correction.) I'd also be inclined to vote for cleaner syntax; many things such as comprehensions are nice, I suppose, but offer no fundamental improvement in expressivity (since one could write the actual function out in any event). This is every bit as provocative as Vlad's email, if not more so ;) From ok@REDACTED Tue Sep 23 07:59:50 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Tue, 23 Sep 2003 17:59:50 +1200 (NZST) Subject: new syntax - a provocation Message-ID: <200309230559.h8N5xoNA011658@atlas.otago.ac.nz> "Vlad Dumitrescu" wrote: * 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. If we want to construct values of such types at run time, there had better be a function which can convert a list of run time values. Suppose it is bitset([X,Y,Z,W]) -> a binary with bits X, Y, Z, and W set (all >= 0). Then the only syntax you need is bitset([3,45,27,39]) *except* that you might want to use it in pattern matches and guards. All it takes is a declaration. For argument's sake, -import_literal(my_stuff, [bitset/1]). with the interpretation (A) "Do the same as -import with the same arguments" AND (B) "Quit compiling now if the module is not loaded into the compiler" AND (C) "working from the leaves of the parse tree to the root, whenever you see a call to a literal import function with constant arguments, call the function and use the value it returns." AND (D) "if there is a call to such a function in a pattern or guard which is _not_ resolved at compile time, provide an intelligible error message and reject the module." This could be prototyped using a transformation module, but - it is the smallest change to Erlang syntax I can think of that would achieve the goal - it requires the least change to Erlang-processing tools such as editor modes - it completely solves the specified problem - it doesn't require new token-level syntax - it makes the link to the module that provides the conversion explicit - lots of other good stuff. * 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? I have found that a Haskell-like syntax for Erlang would fairly consistently yield modules with only 5/8 as many SLOC. I'm a Lisp fan, implementor, and user from way back, but in this case it's exactly the opposite of the right direction. Lisp doesn't get its power from its *concrete* syntax but from its *abstract* syntax. From vlad_dumitrescu@REDACTED Tue Sep 23 08:25:58 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Tue, 23 Sep 2003 08:25:58 +0200 Subject: new syntax - a provocation References: Message-ID: > The one single source, as far as I can tell, of nonlinear algorithms in > Erlang, is an inability to directly address list elements (as per array > subscripts, or similar). Tuples can be used that way. One could imagine using SomeTuple{N} as shorthand for element(N, SomeTuple). If dynamic size is needed, then resizing is somewhat costly, but it is in C too. > I'd also be inclined to vote for cleaner syntax; many things such as > comprehensions are nice, I suppose, but offer no fundamental improvement > in expressivity (since one could write the actual function out in any > event). For me, comprehensions are the cleaner syntax :) They have much more expressive power, even if it's only syntactic sugar. The same applies to records: they only simplify expressions and don't bring anything fundamentally new. But the new level of abstraction is *very* useful anyway. /Vlad From vlad_dumitrescu@REDACTED Tue Sep 23 09:29:15 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Tue, 23 Sep 2003 09:29:15 +0200 Subject: new syntax - a provocation References: <200309230559.h8N5xoNA011658@atlas.otago.ac.nz> Message-ID: From: "Richard A. O'Keefe" > If we want to construct values of such types at run time, there had > better be a function which can convert a list of run time values. > Suppose it is > bitset([X,Y,Z,W]) -> a binary with bits X, Y, Z, and W set (all >= 0). > Then the only syntax you need is > bitset([3,45,27,39]) > *except* that you might want to use it in pattern matches and guards. > > All it takes is a declaration. For argument's sake, > > -import_literal(my_stuff, [bitset/1]). > > with the interpretation > > (A) "Do the same as -import with the same arguments" > AND > (B) "Quit compiling now if the module is not loaded into the compiler" > AND > (C) "working from the leaves of the parse tree to the root, > whenever you see a call to a literal import function with > constant arguments, call the function and use the value it > returns." > AND > (D) "if there is a call to such a function in a pattern or guard which > is _not_ resolved at compile time, provide an intelligible error > message and reject the module." A good idea! Why not let the calls that can't be resolved at compile time expand into a run-time constructor call? Well, at least where this is meaningful. > This could be prototyped using a transformation module, but > - it is the smallest change to Erlang syntax I can think of that would > achieve the goal > - it requires the least change to Erlang-processing tools such as > editor modes > - it completely solves the specified problem > - it doesn't require new token-level syntax > - it makes the link to the module that provides the conversion explicit > - lots of other good stuff. Good points. My original goal was to be able to introduce new types, and to be able to initialize and build the data easily (from a source code point of view). Your way would work fine too, I think. Is it extensible to other similar problems? I think it is. But I still think it might be a good thing to mark in some way that these constructs are special ;-) > Lisp doesn't get its power from its *concrete* syntax but from its > *abstract* syntax. True, but in Lisp's case the two are the same :) /Vlad From mike@REDACTED Tue Sep 23 09:33:43 2003 From: mike@REDACTED (Mike Williams) Date: 23 Sep 2003 07:33:43 GMT Subject: new syntax - a provocation References: Message-ID: 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. 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. /mike In article , 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 |> From vlad_dumitrescu@REDACTED Tue Sep 23 10:00:10 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Tue, 23 Sep 2003 10:00:10 +0200 Subject: new syntax - a provocation References: Message-ID: > 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. Yes, of course. Anything new should be well thought. There is a list with several proposals at http://www.bluetail.com/~rv/Erlang-spec/index.shtml, is that being used? The problem is to find the right balance: not too many new things, not too much old stuff kept for the sake of compatibility. I think records (even if now they show up being not so well specified), list comprehensions and the binary syntax are good things to have been added to the language. There may be more where those came from. Perhaps a way to keep the balance is to have an experimental area to play in, without danger of compromising comercial users. Some things need to be seen and 'felt' to be able to judge their useability. /Vlad From ok@REDACTED Tue Sep 23 10:11:15 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Tue, 23 Sep 2003 20:11:15 +1200 (NZST) Subject: new syntax - a provocation Message-ID: <200309230811.h8N8BFCA032155@atlas.otago.ac.nz> I suggested "-import_literal(Module, Functions)". "Vlad Dumitrescu" replied: A good idea! Why not let the calls that can't be resolved at compile time expand into a run-time constructor call? Well, at least where this is meaningful. That's precisely what I proposed: replace the calls if you can (and, implicitly, but, I thought, obviously, _don't_ replace the calls otherwise) and give an error message if unreplaced calls are left where they are _not_ meaningful. But I still think it might be a good thing to mark in some way that these constructs are special ;-) Well, prefix ? isn't being used for anything _useful_ (:-) (:-) (:-) ... > Lisp doesn't get its power from its *concrete* syntax but from its > *abstract* syntax. True, but in Lisp's case the two are the same :) Would that it were true. When you write a Common Lisp macro, a substantial amount of rewriting may already have been done, and this rewriting may involve forms that were not in the source code and quite possibly could not have be, certainly undocumented stuff. And in Scheme, the "identifiers" that hygienic macros have to worry about are not at all the same as "symbols" that you find in the source code. From vlad_dumitrescu@REDACTED Tue Sep 23 10:33:02 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Tue, 23 Sep 2003 10:33:02 +0200 Subject: new syntax - a provocation References: <200309230811.h8N8BFCA032155@atlas.otago.ac.nz> Message-ID: From: "Richard A. O'Keefe" > That's precisely what I proposed: replace the calls if you can (and, > implicitly, but, I thought, obviously, _don't_ replace the calls otherwise) > and give an error message if unreplaced calls are left where they are _not_ > meaningful. Ok, didn't get that. >> But I still think it might be a good thing to mark in some way >> that these constructs are special ;-) > Well, prefix ? isn't being used for anything _useful_ (:-) (:-) (:-) ... Good point again -- this new stuff can easily be extended to provide real macros (a la Lisp) and then the existing macros will become anyway just particular cases! /Vlad From joe@REDACTED Tue Sep 23 10:42:46 2003 From: joe@REDACTED (Joe Armstrong) Date: Tue, 23 Sep 2003 10:42:46 +0200 (CEST) Subject: new syntax - a provocation In-Reply-To: Message-ID: 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 - <> 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. <> 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" ... :-( <> > > 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 , > 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 > |> > From joe@REDACTED Tue Sep 23 10:53:17 2003 From: joe@REDACTED (Joe Armstrong) Date: Tue, 23 Sep 2003 10:53:17 +0200 (CEST) Subject: soure->source Xformer Message-ID: Question (actually a follow up to my last mail) Has anybody (Luke?, Robert?) got a source->source Erlang transformer that expand out - records - funs - list-comprehensions - if/case/receive I know there is a source->kernel erlang transformer, but I'm after src->src. This is prettry similar to erl_lint + sys_pre_expand only brought up-to-date for list-comprehensions and records. /Joe From vlad_dumitrescu@REDACTED Tue Sep 23 11:08:19 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Tue, 23 Sep 2003 11:08:19 +0200 Subject: new syntax - a provocation References: Message-ID: From: "Joe Armstrong" I'll comment just on a few things. > 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. Yes, this is very true. But if these "nice to have" features are not present and writing code is a pain, with hairy notations and hard to see at a glance structure, then nobody will want to write that code. Or they will develop a nicer abstraction layer on top of it. > IMHO we need to modify Erlang to increase the isolation properties. Can this be done? Where do you think isolation as it is now isn't enough? Flooding another process is one thing - is it really possible to prevent against that? Running exit(Pid, kill) is another. > 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. I am a developer :-) > I think the right thing is to *remove* non-essential stuff and > build on the central core concepts - I think both things should be worked on: the core concepts and a kernel language supporting them efficiently on one hand, and on the other a (more) general programming language, simple, extensible, beautiful to look at (and also maybe with some whistles and bells :). In the end, both will be needed. regards, Vlad From richardc@REDACTED Tue Sep 23 13:09:31 2003 From: richardc@REDACTED (Richard Carlsson) Date: Tue, 23 Sep 2003 13:09:31 +0200 (MET DST) Subject: soure->source Xformer In-Reply-To: References: Message-ID: On Tue, 23 Sep 2003, Joe Armstrong wrote: > Has anybody (Luke?, Robert?) got a source->source Erlang transformer > that expand out > > - records > - funs > - list-comprehensions > - if/case/receive > > This is prettry similar to erl_lint + sys_pre_expand only brought > up-to-date for list-comprehensions and records. sys_pre_expand already *does* expand away records and list comprehensions (do "c(foo, ['E'])." and look at the "foo.E" file). Adding a pass to expand ifs to normal cases should be simple (there used to be a template parse transform file somewhere - under stdlib I think - but I can't find it in the current distribution). Or just hack sys_pre_expand to do it for you - it should not make any difference if it is done there or later (well, the debugger could be confused). Funs should _not_ be "expanded" however, as long as you're still on this level - it's a *big* mistake to expose the actual implementation of closures until you get to the really low level code. /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ "Having users is like optimization: the wise course is to delay it." -- Paul Graham From svenolof@REDACTED Tue Sep 23 11:17:57 2003 From: svenolof@REDACTED (Sven-Olof Nystr|m) Date: Tue, 23 Sep 2003 11:17:57 +0200 Subject: Use-defined guard (was: RE: Enhanced type guard syntax]) In-Reply-To: <16239.4038.633847.469984@gargle.gargle.HOWL> References: <200309220521.h8M5LeJi478902@atlas.otago.ac.nz> <75C3528A-ECD8-11D7-8EDB-000A95927CCE@mac.com> <16239.4038.633847.469984@gargle.gargle.HOWL> Message-ID: <16240.4037.598960.860036@gargle.gargle.HOWL> > > I can't seem to find this proposal online. Link anyone? > > I have a copy. I could post it on the list, if Richard does not have > any objections. See below. Sven-Olof Pattern Abstraction Richard O'Keefe There is one serious defect which Prolog has never overcome, although successor languages such as Mercury have addressed it. It is a defect which languages such as SML, Miranda, Haskell, and Clean do not have, although it is shared by Scheme and Lisp generally. The defect is that Prolog has no support for abstract data types. In fact, Prolog pretty well goes out of its way to discourage abstract data types. Everything in Prolog is a term, and a term is either a variable or a functor applied to arguments which are themselves terms. Not only are there primitive operations (var/1, nonvar/1, functor/3, arg/3) which can be used to compose and decompose any data structure whatever, so that abstraction cannot be enforced, Prolog's normal mode of dealing with data is pattern matching, which means that abstraction is penalised. The classic example is list processing. One can quite easily set up an abstract data type list(T) with operations null([]). pair([H|T], H, T). and then write append(X, Y, Y) :- null(X). append(X, Y, Z) :- pair(X, H,U), pair(Z, H,V), append(U, Y, V). instead of append([], Y, Y). append([H|X1], Y, [H|Z1]) :- append(X1, Y, Z1). but then one has not merely the overhead of calling extra predicates, but the rather disastrous loss of first-argument indexing. All Prolog really needs to solve this problem is a form of predicate definition that is guaranteed to be expanded inline, but this is not one of the matters that the ISO committee chose to address (not the least of the reasons why I have harsh words to say about that committee and that standard). Another thing that would restore indexing would be to use negative clauses such as <- null(L), pair(L, _, _). to declare that null/1 and pair/3 are mutually exclusive. SB-Prolog has for a long time used such knowledge about built-in predicates (notably arithmetic comparison and term comparison) to allow a programmer to write e.g. max(X, Y, X) :- X > Y. max(X, Y, Y) :- X =< Y. and get mutual exclusion of clauses without cuts. However, as Erlang has the typical functional ``commit to first successful match'' rule, it doesn't need negative clauses to get exclusion. Erlang has Prolog-like problems with abstract data types. First, all Erlang data structures are terms, built from variables, constants, pairs, and tuples, and there are primitive features of the language for composing and decomposing terms, so it is quite impossible to enforce encapsulation, at least, not without imposing a type system. Second, Erlang too normally operates on data structures by means of patterns, which literally make the structure of data visible. Unlike Prolog, Erlang does not rely on first-argument (or any other) indexing, but it does not (and should not) allow general user-defined functions in guards, so something like append(X, Y) when empty(X) -> Y; append(X, Y) when {H,T} = pair(X) -> make_pair(H, append(T,Y)). would not be allowed. There are good reasons for this, and I do not want to overturn this feature of Erlang. But we do need something to put in its place if we are to support even weak data abstraction, and we need data abstraction very much if we are going to have 10MSLOC programs that we can hope to trust. (I note that a large chunk of New Zealand was without emergency telephone service for several days in the week just ending, due to a software problem. Probably written in C. (:-)) Note that the disallowed append/2 code I showed above has a rather unpleasant property, which the inlined-simple-predicates approach in Prolog is thankfully free of: composing a pair and decomposing a pair use different forms. This increases the burden on the programmer. There is no symmetry at all that can be exploited to make the correspondence easier to remember. There is another major property which a good solution to the problem should have: it should be fully compatible with an entire absence of any preprocessor. At the end of this note I shall explain what is badly wrong with records in Erlang. The pattern abstraction proposal is quite simple. There are three ways an abstract pattern can be used: - to compose a term - to decompose a term - to update a term (that is, compose a new term similar to an old one with some differences. A pattern definition is basically a restricted kind of function definition, which is rewritten to define a composition function, a decomposition function, and an update function. Each of the three ways of using an abstract pattern is defined by rewriting to a call to one of the three derived functions. Abstract patterns begin with a sharp, like records. Unlike records, they use round parentheses instead of curly braces. Also unlike records, they are executable code, not a kind of macro, so they may come from modules other than the lexically enclosing one. A pattern definition is a restricted function definition whose heads are decorated with a sharp and whose bodies are patterns (possibly involving other abstract patterns). definition +:= patclause {';' patclause}... '.' patclause ::= '#' head ['when' guard] '->' pattern pattern +:= '#' [module ':'] name '(' [patterns.] ')' primary +:= '#' [module ':'] name '(' [expressions] ')' | primary '#' [module ':'] name '(' [expressions] ')' Here's append/2 using abstract patterns. #empty() -> []. #pair(H,T) -> [H|T]. #head(H) -> [H|_]. #tail(T) -> [_|T]. append1(#empty(), Y) -> Y; append1(#pair(H,T), Y) -> #pair(H,append1(T,Y)). append2(#empty(), Y) -> Y; append2(#head(H)=#tail(T), Y) -> #pair(H,append2(T,Y)). What does this mean? A pattern definition basically defines three functions: a function to use for composition, a function to use for decomposition, and a function to use for update. For the sake of exposition, let's name the composition function for #x/n '#x'/n, the decomposition function 'n=x'/1, and the update function '!x'/n+1. '#empty'() -> []. % composition function '0=empty'([]) -> {}. % decomposition function '!empty'([]) -> []. % update function '#pair'(H,T) -> [H|T]. '2=pair'([H|T]) -> {H,T}. '!pair'([_|_], H,T) -> [H|T]. '#head'(H) -> error(). % useless composition function '1=head'([H|_]) -> H. '!head([_|T], H) -> [H|T]. '#tail'(T) -> error(). % useless composition function '1=tail'([_|T]) -> T. '!tail'([H|_], T) -> [H|T]. append1(X, Y) when {} = '0=empty'(X) -> Y; append1(X, Y) when {H,T} = '2=pair'(X) -> '#pair'(H, append1(T,Y)). append2(X, Y) when {} = '0=empty'(X) -> Y; append2(X, Y) when H = '1=head'(X), T = '1=tail'(Y) -> '#pair'(H, append2(T,Y)). After inline expansion, these two definitions would be identical to each other and to the usual definition. Suppose we are given a pattern definition #p(P11,...,P1n) when G1 -> Q1; ... #p(Pk1,...,Pkn) when Gk -> Qk. The composition function is obtained very simply by turning #p into '#p'. The decomposition function basically switches the left and right sides: 'n=p'(Q1) when G1 -> {P11,...,P1n}; ... 'n=p'(Qk) when Gk -> {Pk1,...,Pkn}. However, for the sake of field selection notation, and for efficiency, the translation is simplified when n=1: '1=p'(Q1) when G1 -> P11; ... '1=p'(Qk) when Gk -> Pk1. The update function has to copy the bits that aren't mentioned and replace the bits that are. Define Q'i to be Qi with anonymous variables replaced by new variables, Q"i and G"i to be Q'i and Gi with the original named variables consistently replaced by new variables. Then we get '!p'(Q"1,P11,...,P1n) when G"1 -> Q'1; ... '!p'(Q"k,Pk1,...,Pkn) when G"k -> Q'k. All of these translations have to make sense. In particular: 1. every variable used in a guard must be defined in both the argument patterns and the replacement pattern corresponding. 2a. If the composition function is to be usable, Qi must be fully determined by Pi1...Pin and Gi, that is, have no variable, anonymous or otherwise, that is not assigned a value by them. 2b. On the other hand, if an update function is to be useful, there should be some anonymous variables in Qi, or else why not just use a composition function? 3. Pij must be fully determined by Qi and Gi, that is, have no variable, anonymous or otherwise, that is not assigned a value by them. This actually turns out to be too strict. There is no point in having an abstract pattern that can only be used for composition; we already have perfectly good functions for that. But there is some sense in having an abstract pattern that can only be used for decomposition. Accordingly, if condition 2a is violated by the ith clause, that clause of the composition function becomes '#p'(Pi1,...,Pin) when Gi -> error(...) When an abstract pattern is invoked as part of a pattern, #[m:]p(P1,...,Pn) = E it is as if {P1,...,Pn} = [m:]'n=p'(E) were invoked instead, if n~=1, or as if P1 = [m:]'1=p'(E) were invoked, if n=1. Since abstract patterns are state independent and have no side effects, it doesn't matter whether the translation preserves left to right order or not; suffice it that pattern match translation can preserve left to right order if we want. If #p/1 is an abstract pattern, it may also be invoked as a field reference: E0#p is as if '1=p'(E0) had appeared instead. This applies to guard expressions as well as general expressions. Note that E#p is different from #p(E). When an abstract pattern is invoked as part of an expression, #[m:]p(E1,...,En) it is as if [m:]'#p'(E1,...,En) were invoked instead. This clearly preserves the order and embedding of expressions, so left to right execution order is not at all disturbed. When an abstract pattern is invoked for update, V = E0#[m:]p(E1,...,En) it is as if V = [m:]'!p'(E0, E1,...,En) were invoked instead. The only way this could perturb left to right ordering is if the module prefix involved an expression other than a variable or atom, and in that case the translation (ET = E0, V = m:'!p'(ET, E1, ..., En) can be used (assuming that Erlang does or will allow arbitrary primaries as module prefixes) where ET is a new variable. The preservation of left to right order is why the `base datum' argument of an update function is the first rather than the last. There is one further condition. At the moment, if P is any pattern, and P = P makes sense, (mainly, P contains no unbound variables), we expect it to be true. But consider #p(1) -> []; #p(2) -> []. Y = #p(2), #p(2) = Y will fail, because it turns into '#p'(1) -> []; '#p'(2) -> []. '1=p'([]) -> 1; '1=p'([]) -> 2. '!p'([],1) -> []; '!p'([],2) -> []. Y = '#p'(2), 2 = '1=p'(Y) The conditions we need are easy to state 4. There does not exist any term T such that Qi = T, Gi ==> true Qj = T, Gj ==> true i ~= j. 5. There do not exist any terms T1,...,Tn such that Pi1 = T1, ..., Pin = Tn, Gi ==> true Pj1 = T1, ..., Pjn = Tn, Gj ==> true i ~= j but are less easy to check. The example clearly violates condition 4. The difficulty of checking these conditions (a decision procedure for arithmetic appears to be required) would at first sight appear to be a problem, but in fact there are good reasons not to impose them, Now let's look at an example. ---------------------------------------------------------------- Queue package example. We'll implement queues twice. -module(queue). -export([#empty/0,#nonempty/1,push/2,pop/1]). #empty() -> []. #nonempty() -> [_|_]. % violates condition 2 push(Q, X) -> append(Q, [X]). pop([X|Q]) -> {X,Q}. %end. -module(queue). -export([#empty/0,#nonempty/1,push/2,pop/2]). #empty() -> {[],[]}. #nonempty() -> {[_|_],_}; % violates condition 2 #nonempty() -> {[],[_|_]}. % violates condition 2 push({L,R}, X) -> {L,[X|R]}. pop({[X|L],R}) -> {X,{L,R}}; pop({[],R}) -> [X|L] = reverse(R), {X,L}. %end. -module(bfs). -export(bfs/1). -import(problem, [solved/1,children/1]). -import(queue, [#empty/0,#nonempty/1,push/2,pop/1]). bfs(Start) -> loop(push(#empty(), Start)). loop(#empty()) -> undefined; loop(Q = #nonempty()) -> {X,P} = top(Q), case solved(X) of true -> X; false -> loop(pushall(P, children(X))) end. pushall(Q, []) -> Q; pushall(Q, [H|T]) -> pushall(push(Q,H), T). %end. Here's the translation of the bfs module: -module(bfs). -export(bfs/1). bfs(Start) -> loop(queue:push(queue:'#empty'(), Start)). loop(Q) when {} = queue:'0=empty'(Q) -> undefined; loop(Q) when {} = queue:'0=nonempty'(Q) -> {X,P} = queue:pop(Q), case problem:solved(X) of true -> X; false -> loop(pushall(P, problem:children(X))) end. pushall(Q, []) -> Q; pushall(Q, [H|T]) -> pushall(queue:push(Q,H), T). %end. I have argued elsewhere that there should be two directives -use_early(module, [used functors]). -use_late(module, [used functors]). which indicate that specified functors from a specified module are used, the former indicating early binding, neither of them indicating that a name is imported into the local scope. One reason for that was to capture the good aspect of the preprocessor, which is precisely early binding. But note that if we used the preprocessor to hide the implementation of queues from the programmer while revealing it to the compiler, we would have to use early binding, while with abstract patterns, that's an independent choice. The bfs module can use #empty() and #nonempty() as patterns without requiring early binding Note that replacing one version of the queue module by another while bfs/1 was running would not be a good idea. This seems to be quite typical, and I do not understand how Erlang avoids serious trouble. The problem is that once the bfs/1 function has received a data structure from the queue module, it depends on the queue module still accepting the same data structure, so the process running bfs/1 depends on the queue module even when it is not calling a function from that module. There really needs to be some sort of locking facility so that bfs/1 could be written bfs(start) -> with_module_lock(queue, loop(push(#empty(), Start))). However, if we are aware that there are long-lived processes that have data structures of the old form that need to be supported for a while, we might choose to write a queue module that supports both forms, while preferring the new one, and it is for this reason that abstract patterns may have more than one clause. (Although the second version of the queue modules needs this anyway.) Here goes: -module(queue). -export([#empty/0,#nonempty/1,push/2,pop/1]). #empty() -> {[],[]}; #empty() -> []. % violates condition 5 #nonempty() -> {[_|_],_}; #nonempty() -> {[],[_|_]}; #nonempty() -> [_|_]. % violates condition 5 push({L,R}, X) -> {L,[X|R]}; push(Q, X) -> append(Q, [X]). pop({[X|L],R}) -> {X,{L,R}}; pop({[],R}) -> [X|L] = reverse(R), {X,L}; pop([X|Q]) -> {X,Q}. %end. Try doing that with macros! Of course, macros provide early binding and inlining in one easy step, which may (but need not) be good for efficiency. If an abstract pattern is defined in the module that uses it, or if -use_early is defined, then early binding occurs, and inlining is a possibility. The option of inlining may be better than the certainty of inlining. Why? The first, and perhaps most obvious, reason is that abstract patterns are named code forms with well defined invocation and contents, just like functions. The fact that they can be used without requiring inlining is good news for debuggers and interpreters, not to mention test coverage analysers and profilers. The second is that inlining doesn't always help efficiency. There's no point in executing 10% fewer instructions if, thanks to cache effects, it takes 20% longer to do so. Back in the late 80s at Quintus, a certain competitor claimed that their native-code Prolog system generated code that ran twice as fast as ours. So it did, on naive reverse. On a two-page program (which didn't fit into the 68020's on-chip instruction cache), it did no better than our threaded-code system. On a real program, it was twice as slow. I have heard that the same phenomenon occurred with BEAM -vs- JAM. Inlining can have similar effects, though less severe. One extension to Erlang would make it easier to inline abstract patterns, and that is disjunctive guards. Currently, we have guard ::= ... '(' guard ')' replace that by guard ::= ... '(' guard {'|' guard}... ')' with the obvious semantics. This would be useful anyway. ---------------------------------------------------------------- What's wrong with records? Records tangle up several things: 1 the possibility of naming a pattern 2 field and update notation. 3 keyword and default arguments 4 a very specific data structure 5 a global name space 6 the possibility of unchecked conflicting definitions in that namespace 7 a requirement to use the preprocessor to get weak abstraction 8 syntax that includes what LOOK like pattern matches but aren't. Some of these are good (1, 2, 3), some of them are less good (4), some of them are bad (5 and 8) and some of them are very bad (6 and 7). Pattern abstraction provides (1 and 2) without any of the others. What's wrong with (4)? First, it means that records actually give us no abstraction at all; in the Erlang Standard specification, to be a record of type T is precisely to be a tuple of a particular arity whose first element is the atom T. Second, if we want to give a name to some other structure, we are sunk, as records buy us nothing. Here is a realistic example. Suppose we want to manipulate timestamps. For compatibility with current Erlang, we might want these timestamps to contain embedded date and time values. So #timestamp() -> {_, _}. #timestamp(DT,TM) -> {DT, TM}. #timestamp(Y,M,D,H,I,S) -> {{Y,M,D},{H,I,S}}. #time_date(DT) -> {DT,_}. #time_date(Y,M,D) -> {{Y,M,D},_}. #time_time(TM) -> {_,TM}. #time_time(H,I,S) -> {_,{H,I,S}}. #time_year(Y) -> {{Y,_,_},_}. #time_month(M) -> {{_,M,_},_}. #time_day(D) -> {{_,_,D},_}. #time_hour(H) -> {_,{H,_,_}}. #time_minute(I) -> {_,{_,I,_}}. #time_second(S) -> {_,{_,_,S}}. Eventually, we purge our code of explicit references to the patterns, and can switch to a more space-efficient representation: #timestamp() -> {_,_,_,_,_,_}. #timestamp({Y,M,D},{H,I,S}}) -> {Y,M,D,H,I,S}. #timestamp(Y,M,D,H,I,S) -> {Y,M,D,H,I,S}. #time_date({Y,M,D}) -> {Y,M,D,_,_,_}. #time_date(Y, M, D) -> {Y,M,D,_,_,_}. #time_time({H,I,S}) -> {_,_,_,H,I,S}. #time_time(H, I, S) -> {_,_,_,H,I,S}. #time_year(Y) -> {Y,_,_,_,_,_}. #time_month(M) -> {_,M,_,_,_,_}. #time_day(D) -> {_,_,D,_,_,_}. #time_hour(H) -> {_,_,_,H,_,_}. #time_minute(I) -> {_,_,_,_,I,_}. #time_second(S) -> {_,_,_,_,_,S}. What do we have here? A change of representation. What is it that records do not allow you to vary? The representation (except within very narrow limits). Just to resume a topic that may not have been clear before, here are the functions we get for the first of these definition sets. '#timestamp'() -> error(). '0=timestamp'({_,_}) -> {}. '!timestamp'({X1,X2}) -> {X1,X2}. '#timestamp'(DT, TM) -> {DT, TM}. '2=timestamp'({DT,TM}) -> {DT, TM}. '!timestamp'({X1,X2}, DT, TM) -> {DT,TM}. '#timestamp'(Y,M,D,H,I,S) -> {{Y,M,D},{H,I,S}}. '6=timestamp'({{Y,M,D},{H,I,S}}) -> {Y,M,D,H,I,S}. '!timestamp'({{X1,X2,X3},{X4,X5,X6}},Y,D,M,H,I,S) -> {{Y,M,D},{H,I,S}}. '#time_date'(DT) -> error(). '1=time_date'({DT,_}) -> DT. '!time_date'({X2,X1}, DT) -> {DT,X1}. '#time_date'(Y,M,D) -> {{Y,M,D},_}. '3=time_date'({{Y,M,D},_}) -> {Y,M,D}. '!time_date'({X2,X1}, Y, M, D) -> {{Y,M,D},X1}. '#time_time'(TM) -> error(). '1=time_time'({_,TM}) -> TM. '!time_time'({X1,X2}, TM) -> {X1,TM}. #time_time(H,I,S) -> error(). '3=time_time'({_,{H,I,S}}) -> {H,I,S}. '!time_time'({X1,X2}, H, I, S) -> {X1,{H,I,S}}. '#time_year'(Y) -> error(). '1=time_year'({{Y,_,_},_}) -> Y. '!time_year'({X4,X1,X2},X3}) -> {{Y,X1,X2},X3}. '#time_month'(M) -> error(). '1=time_month'({{_,M,_},_}) -> M. '!time_month'({X1,X4,X2},X3}, M) -> {{X1,M,X2},X3}. '#time_day'(D) -> error(). '1=time_day'({{_,_,D},_}) -> D. '!time_day'({X1,X2,X4},X3}, D) -> {{X1,X2,D},X3}. '#time_hour'(H) -> error(). '1=time_hour'({_,{H,_,_}}) -> H. '!time_hour'({X1,{X4,X2,X3}}, H) -> {X1,{H,X2,X3}}. '#time_minute'(I) -> error(). '1=time_minute'({_,{_,I,_}}) -> I. '!time_minute'({X1,{X2,X4,X3}}, I) -> {X1,{X2,I,X3}}. '#time_second'(S) -> error(). '1=time_second'({_,{_,_,S}}) -> S. '!time_second'({X1,{X2,X3,X4}}, S) -> {X1,{X2,X3,S}}. So if, for example, we wanted to refer to noon today, or to find what year it is, we could write Noon_Today = timestamp:now()#time_time(12,0,0), This_Year = timestamp:now()#time_year and these would work whether a timestamp was stored as one tuple or three. The -record approach cannot be used with the three tuple version. (It can't be used with the one tuple version either, because there must be an atom serving as a tag, and it must be the first element of the tuple, and it must be the same as the record name.) What about keyword and default arguments (3)? Are they not a benefit of using records? Yes, they are. But they should be available for all functions and abstract patterns, not just records. Perhaps it is unfair to say ``ask an Ada programmer'', because Ada doesn't use data the way Erlang does. But Ada programs do have lots of procedure and function calls, just as Erlang does, and Erlang functions need more arguments than Ada functions, for the same reasons as Prolog, so need keyword and default arguments more than Ada does. I intend that abstract patterns should use whatever method is used to provide that feature for general functions. Do records really imply a global namespace? Yes, because the record name appears inside the record. Consider: -module(a). -record(r, {X,Y,Z}). ... f(..R..) when record(R, r) -> -module(b). -record(r, {X,Y}). g(R) when record(R, r) -> f(R). ... g(#r{1,2}) ... It is not clear exactly what the record/2 guard test should do. One manual says "This test checks that R is a tuple of arity N+1, where N is the number of fields in the record, and the first element in the tuple is the" atom naming the record. This means that g/1 WILL believe that record(R, r) is true, but f/1 will NOT. That does mean that f/1 will not be tricked into working with something that doesn't match its idea of what an `r' record looks like, but programmers will find it very confusing that record(R,r) can succeed in one module and fail in another. It is also a nuisance that we cannot tell whether something "is a record of type r" without having a -record declaration in scope. That doesn't apply to any other guard test. The real problem comes when a and b agree on the arity of r but disagree on the argument order or interpretation. Consider again, -module(a). -record(r, {X,Y,Z}). ... f(...#r(X,Y,Z)...) -> ... -module(b). -record(r, {Z,Y,X}). ... f(...#r(Z,Y,X)...) Either a global namespace for records is enforced (so that the record/2 guard test works consistently), or serious confusion may result. The snag here is that a record name ought to be `owned' by some module, but in fact it is `owned' by a preprocessor file. How do pattern abstractions address this problem? In part, it must be admitted, they don't. They are weak abstractions; there is no defence against forgery, and little defence against accident other than adding a tag, just like records. The advantage comes from the fact that an abstract pattern is clearly owned by a specific module; there is one declaration, not multiple copies of a declaration. Abstract pattern names are module qualified, just like other function names. There is something that could be done that would make accident unlikely and forgery slightly harder. Records differ from tuples in that they are tagged. The tags cannot be module-specific, because the same declaration may be copied into many modules, with no clue as to which is the owner. All we do is take the idea of tagging, and bend the existing module-specific literal syntax (like ?VERSION and ?MODULE) a little bit. The directive -unique(name). would mean that at load time a new ref() would be created and bound to name, in such a way that the name can be recovered from the ref() for debugging purposes, and at compile time each occurrence of ?name would refer to that ref(). (This is like the classic Lisp hack of using a unique cons cell or function closure as a tag.) Then we could write -unique(ts). #timestamp() -> {?ts,_, _}. #timestamp(DT,TM) -> {?ts,DT, TM}. #timestamp(Y,M,D,H,I,S) -> {?ts,{Y,M,D},{H,I,S}}. #time_date(DT) -> {?ts,DT,_}. #time_date(Y,M,D) -> {?ts,{Y,M,D},_}. #time_time(TM) -> {?ts,_,TM}. #time_time(H,I,S) -> {?ts,_,{H,I,S}}. #time_year(Y) -> {?ts,{Y,_,_},_}. #time_month(M) -> {?ts,{_,M,_},_}. #time_day(D) -> {?ts,{_,_,D},_}. #time_hour(H) -> {?ts,_,{H,_,_}}. #time_minute(I) -> {?ts,_,{_,I,_}}. #time_second(S) -> {?ts,_,{_,_,S}}. This is admittedly clumsy, but it's the idea I want to push, not the syntax, which is at least local to the owning module. This looks a bit like the preprocessor, but it only requires recognising ? as a special form. If we left the question mark off (and the binding to a ref()) we would have the same insecure approach as records, without the requirement of a fixed location for the tag. Thanks to preprocessor use, that insecurity is real. The really nasty thing happens when module a gets its record declaration from foo.hrl, module a is compiled and loaded, foo.hrl is changed, and another module including (the revised version of) foo.hrl is compiled and loaded. We have a dependency between module a and foo.hrl which is not noticed; partly because foo.hrl is not a module and is not, as such, loaded, and partly because the dependency exists even while the code in foo.hrl is not running. So we are left with only one thing that abstract patterns cannot do as well as records or better, than that is keyword and default parameters. At one time it was expected that records would become new types; this seems to have been dropped from the current Erlang Standard specification (0.6); I surmise because of the difficulty of establishing an `owner'. There is one more thing that abstract patterns can do that records as currently defined in Erlang cannot do, and that is enforce type constraints on components. Consider triangles. We'd like a triangle to be represented by a `record' containing three floats. Using record notation, all we can do is write -record(triangle{A,B,C}). and hope. Using abstract pattern notation, we can write #triangle(A,B,C) when float(A), float(B), float(C) -> {A,t,B,C}. and this will enforce the type constraints on the components. Here is a sample use of this pattern, to see whether a value of this type is a plausible triangle. plausible(#triangle(A,B,C)) when 0 < A, A <= B+C, 0 < B, B <= C+A, 0 < C, C <= A+B -> true; plausible(_) -> false. After translation and inline expansion, plausible/1 becomes plausible({A,t,B,C}) % check form when float(A), float(B), float(C), % check types 0 < A, A <= B+C, 0 < B, B <= C+A, 0 < C, C <= A+B -> true; plausible(_) -> false. This ability to propagate type information/checking from the declaration to the uses, if the programmer wants it, is an important safety feature that is completely missing from Erlang records, and is obtained without any new runtime machinery. Note that an Erlang compiler can easily deduce from the use of A, B, C that they must be some kind of number, but not which kind, not without interprocedural data flow analysis. Even without inlining, we get the runtime type checking we choose in the declaration, which has to be helpful if we want to build large systems. The End. The abstract pattern notation neatly replaces both the record declarations and the use of the preprocessor. Records let you say L2 = L#log{blocked_by = none, status = ok} which is arguably prettier than L2 = L#log_blocked_by(none)#log_status(ok) but not hugely so. One could argue that the abstract pattern version has the merit of not containing a manifestly false pattern match 'status = ok'. Records automatically provide you with a full set of record.field forms; abstract patterns for them have to be separately declared. On the other hand, records *force* you to accept a full set of record.field forms even if you want some of them blocked, and it is not at all clear how import/export of #record.field forms would be controlled. Records permit patterns like #log{status == S, users = N} = L which is arguably prettier than #log_status(S) = #log_users(N) = L but again, the latter never contains manifestly absurd matches. Dynamic Patterns. The parallel between abstract patterns and functions can be stretched a little further. In effect, we can regard a value of type (T1,...,Tn) => T0 [where => is the pattern arrow in distinction to the function arrow ->] as a record ( b : (T1,...,Tn) -> T0 % building u : (T0,T1,...,Tn) -> T0 % updating d : T0 -> (T1,...,Tn) % decomposing ) and X = #p(E1,...,En) ==> X = p.b(E1,...,En) X = E0#p(E1,...,En) ==> X = p.u(E0,E1,...,En) #p(P1,...,Pn) = E ==> {P1,...,Pn} = p.d(E) Since a triple of functions can be passed as a value, why not allow a pattern to be passed as a value? Let's put this in Erlang terms. Define #E0(E1,...,En) where E0 is not an atom or a module:atom pair to be #apply(E0, [E1,...,En]) Define #apply(Mod,E0,EL) to be #apply({Mod,E0}, EL) Now we have to define the use of #apply/2. X = #apply(MF,L) where MF = {M,F}, L = [T1,...,Tn}, and M, F are atoms reduces to X = #M:F(T1,...,Tn), i.e. X = M:'#F'(T1,...,Tn). where MF is the result of (fun #F/N) executed statically within module M, L = [T1,...,Tn], and N = n, reduces to X = #M:F(T1,...,Tn) X = E0#apply(MF,L) where MF = {M,F}, L = {T1,...,Tn} and M, F are atoms reduces to X = E0#M:F(T1,...,Tn) i.e. X = M:'!F'(E0,T1,...,Tn) where MF is the result of (fun #F/N) executed statically within module M, L = [T1,...,Tn], and N = n, reduces to X = Eo#M:F(T1,...,Tn). #apply(MF, [P1,...,Pn]) = E where MF is statically a GuardExpression whose value is dynamically {M,F} for M and F atoms, and [P1,...,Pn] is statically a list of Patterns, reduces to #M:F(P1,...,Pn) = E, i.e. {P1,..,Pn} = M:'n=F'(E). where MF is statically a GuardExpression whose value is dynamically the result of (fun #F/N) executed statically within a module M, [P1,...,Pn] is statically a list of Patterns, and N = n, reduces to #M:F(P1,...,Pn) = E. Now we can do things like this: proj(P, []) -> []; proj(P, [#P(X)|Xs[) -> [X|proj(P,Xs)]. #unit_list(X) -> [X]. #unit_tuple(X) -> {X}. ... proj(fun #unit_list/1, L), ... ... proj(fun #unit_tuple/1, LT), ... By bending explicit fun syntax a little bit, we can even get anonymous patterns: fun #( Pattern... ) when Guard -> Pattern ; #( Pattern... ) when Guard -> Pattern ... end e.g. fun #(X) -> [X|_] end is an anonymous `hd' pattern. (The syntax here is based on two rules: to get pattern syntax from function syntax, put # in front of the [Module:]Name, and to get explicit fun syntax, put `fun' `end' around the clauses and delete the function Name.) It's not that I think anonymous patterns are wildly useful; the point is that if they weren't at least thinkable the parallels between patterns and functions would be sploit, to the detriment of our ability to reason correctly about them. Try doing that with records! As a matter of fact, dynamic patterns do something for us that isn't easy to get any other way. Look at prof/2 again. Is there any nonsyntactic difference between proj(P, []) -> []; proj(P, [#P(X)|Xs]) -> [X|proj(P, Xs)]. and map(F, []) -> []; map(F, [X|Xs]) -> [F(X)|map(F, Xs)]. or is it just a piece of `cuteness' that lets you put the function call on the `wrong' side? Yes, there is a difference. The function F in map/2 may do anything at all; it may have side effects, it may allocate arbitrarily large amounts of storage, it may run for huge amounts of time. The pattern P in proj/2 must be an abstraction of a pattern-and-guard: it may not send or receive messages, have any other side effects, allocate huge amounts of storage, or take unbounded amounts of time. It is forced to be well behaved in ways that an arbitary function parameter is not. Indeed, we are sure that the value X it returns in proj/2 is part of the term it matches, so it really is a projection function. If we want to reason about the effects of a code fragment, proj/2 is significantly easier to reason about than map/2. This means that anonymous patterns do have a use: proj(fun #(X) -> {X,_,_} end, L) is trivially well-behaved, whereas map(fun ({X,_,_}) -> X end, L) requires more analysis to see its harmlessness. (Of course, checking higher order functions is never entirely trivial, and it is something of a pity that they were added to Erlang so hastily. Topic for another working paper.) When you've invented a language construct, a good sign that you are onto something worthwhile is that applications come faster than you have time to write them down. When I wrote the stuff about dynamic abstract patterns, I didn't have an application in mind. But I suddently realised that there was a proposal I thought of last year which had been languishing because there was no safe way to do it. Erlang processes are vulnerable to a denial-of-service attack where a malicious or erroneous process repeatedly sends "junk mail". The Erlang documentation recommends that most or all 'receive' commands should include a wildcard case to discard junk mail, but that has the disadvantage that it won't discard junk mail until the process actually executes a receive. Junk mail can pile up while a process is suspended. If nothing else, it causes the recipient of the junk mail to pay (in processing and garbage collection time) to inspect it. Last year I came up with the idea of a 'message filter'. set_process_filter(fun (Msg) -> ... true | false end) would mean that whenever a (local) process send a message to this one, the message filter function would run IN THE SENDER'S THREAD to see if the message was ok. If it returned 'false', the message would be discarded, otherwise it would be retained. The problem with that is that it makes the sender vulnerable to Trojan horses; the message filter function could do absolutely anything while masquerading as the sender. What I needed was a way of declaring and enforcing that the message filter function would execute in bounded time with no side effects. Does that sound familiar? It's basically an abstract pattern. So here's the new proposal. set_process_filter(fun #() when Guard -> Pattern end) If the argument is a pattern expression of arity 0, then when a message is sent to this process, the pattern will be executed in the sender's thread and if it matches the message will be sent and if it fails the message will be discarded. set_process_filter(fun #(Result) when Guard -> Pattern end) If the argument is a pattern expression of arity 1, then when a message is sent to this process, the pattern will be executed in the sender's thread, and if it matches, the Result will be sent, and if it fails, the message will be discarded. Of course these forms are only illustrative; there could be any number of clauses and fun #F/0 or fun #F/1 could be used instead. The use of set_process_filter/1 would be to allow simple protocol conversions. Whether this feature is as useful as I think is debatable; Tobbe argues that the best idea is to conceal processes inside their creating modules, and I think he's probably right about that. The point is that dynamic functions whose cost is certainly bounded are a useful thing to have, and they fall out quite naturally from trying to take abstract patterns seriously. From erlang@REDACTED Tue Sep 23 09:50:06 2003 From: erlang@REDACTED (Inswitch Solutions - Erlang Evaluation) Date: Tue, 23 Sep 2003 09:50:06 +0200 Subject: c:m() output to variable Message-ID: <001201c381a7$4f363520$1e00a8c0@design> Does anyone know if there is a way to store the output of c:m() in a variable? L = c:m(). Thank in avdance, Eduardo Figoli INSwitch Solutions -------------- next part -------------- An HTML attachment was scrubbed... URL: From luke@REDACTED Tue Sep 23 14:57:45 2003 From: luke@REDACTED (Luke Gorrie) Date: 23 Sep 2003 14:57:45 +0200 Subject: c:m() output to variable In-Reply-To: <001201c381a7$4f363520$1e00a8c0@design> References: <001201c381a7$4f363520$1e00a8c0@design> Message-ID: "Inswitch Solutions - Erlang Evaluation" writes: > Does anyone know if there is a way to store the output of c:m() in a variable? > L = c:m(). If bring up c.erl, the definition is: m() -> mformat("Module", "File"), foreach(fun ({Mod,File}) -> mformat(Mod, File) end, sort(code:all_loaded())). mformat(A1, A2) -> format("~-20s ~s\n", [A1,A2]). So code:all_loaded() is most of what you want. -Luke From fredrik.linder@REDACTED Tue Sep 23 14:52:58 2003 From: fredrik.linder@REDACTED (Fredrik Linder) Date: Tue, 23 Sep 2003 14:52:58 +0200 Subject: Use-defined guard (was: RE: Enhanced type guard syntax]) In-Reply-To: <16240.4037.598960.860036@gargle.gargle.HOWL> Message-ID: Yes, this is exactly what I wish for. :-) Erlangers, is there any possibility that this will be added? Cheers /Fredrik > -----Original Message----- > From: Sven-Olof Nystr|m [mailto:svenolof@REDACTED] > Sent: den 23 september 2003 11:18 > To: Sven-Olof Nystr|m > Cc: Sean Hinde; Richard A. O'Keefe; erlang-questions@REDACTED; > fredrik.linder@REDACTED > Subject: Re: Use-defined guard (was: RE: Enhanced type guard syntax]) > > > > > I can't seem to find this proposal online. Link anyone? > > > > I have a copy. I could post it on the list, if Richard does not have > > any objections. > > See below. > > Sven-Olof > > > > > > Pattern Abstraction > > Richard O'Keefe > > > There is one serious defect which Prolog has never overcome, although > successor languages such as Mercury have addressed it. It is a defect > which languages such as SML, Miranda, Haskell, and Clean do not have, > although it is shared by Scheme and Lisp generally. > > The defect is that Prolog has no support for abstract data types. In > fact, Prolog pretty well goes out of its way to discourage abstract data > types. Everything in Prolog is a term, and a term is either a variable > or a functor applied to arguments which are themselves terms. Not only > are there primitive operations (var/1, nonvar/1, functor/3, arg/3) which > can be used to compose and decompose any data structure whatever, so > that abstraction cannot be enforced, Prolog's normal mode of dealing > with data is pattern matching, which means that abstraction is > penalised. > > The classic example is list processing. One can quite easily set up an > abstract data type list(T) with operations > > null([]). > > pair([H|T], H, T). > > and then write > > append(X, Y, Y) :- null(X). > append(X, Y, Z) :- pair(X, H,U), pair(Z, H,V), append(U, Y, V). > > instead of > > append([], Y, Y). > append([H|X1], Y, [H|Z1]) :- append(X1, Y, Z1). > > but then one has not merely the overhead of calling extra predicates, > but the rather disastrous loss of first-argument indexing. All Prolog > really needs to solve this problem is a form of predicate definition > that is guaranteed to be expanded inline, but this is not one of the > matters that the ISO committee chose to address (not the least of the > reasons why I have harsh words to say about that committee and that > standard). Another thing that would restore indexing would be to use > negative clauses such as > > <- null(L), pair(L, _, _). > > to declare that null/1 and pair/3 are mutually exclusive. SB-Prolog > has for a long time used such knowledge about built-in predicates > (notably arithmetic comparison and term comparison) to allow a programmer > to write e.g. > > max(X, Y, X) :- X > Y. > max(X, Y, Y) :- X =< Y. > > and get mutual exclusion of clauses without cuts. However, as Erlang > has the typical functional ``commit to first successful match'' rule, > it doesn't need negative clauses to get exclusion. > > Erlang has Prolog-like problems with abstract data types. First, all > Erlang data structures are terms, built from variables, constants, > pairs, and tuples, and there are primitive features of the language for > composing and decomposing terms, so it is quite impossible to enforce > encapsulation, at least, not without imposing a type system. Second, > Erlang too normally operates on data structures by means of patterns, > which literally make the structure of data visible. Unlike Prolog, > Erlang does not rely on first-argument (or any other) indexing, but it > does not (and should not) allow general user-defined functions in > guards, so something like > > append(X, Y) when empty(X) -> Y; > append(X, Y) when {H,T} = pair(X) -> make_pair(H, append(T,Y)). > > would not be allowed. There are good reasons for this, and I do not > want to overturn this feature of Erlang. But we do need something to > put in its place if we are to support even weak data abstraction, and we > need data abstraction very much if we are going to have 10MSLOC programs > that we can hope to trust. (I note that a large chunk of New Zealand > was without emergency telephone service for several days in the week > just ending, due to a software problem. Probably written in C. (:-)) > > Note that the disallowed append/2 code I showed above has a rather > unpleasant property, which the inlined-simple-predicates approach in > Prolog is thankfully free of: composing a pair and decomposing a pair > use different forms. This increases the burden on the programmer. > There is no symmetry at all that can be exploited to make the > correspondence easier to remember. > > There is another major property which a good solution to the problem > should have: it should be fully compatible with an entire absence of > any preprocessor. At the end of this note I shall explain what is badly > wrong with records in Erlang. > > The pattern abstraction proposal is quite simple. There are three ways > an abstract pattern can be used: > - to compose a term > - to decompose a term > - to update a term (that is, compose a new term similar to an old one with > some differences. > A pattern definition is basically a restricted kind of function > definition, which is rewritten to define a composition function, a > decomposition function, and an update function. Each of the three ways > of using an abstract pattern is defined by rewriting to a call to one of > the three derived functions. > > Abstract patterns begin with a sharp, like records. Unlike records, > they use round parentheses instead of curly braces. Also unlike > records, they are executable code, not a kind of macro, so they may come > from modules other than the lexically enclosing one. A pattern > definition is a restricted function definition whose heads are decorated > with a sharp and whose bodies are patterns (possibly involving other > abstract patterns). > > definition +:= patclause {';' patclause}... '.' > > patclause ::= '#' head ['when' guard] '->' pattern > > pattern +:= '#' [module ':'] name '(' [patterns.] ')' > > primary +:= '#' [module ':'] name '(' [expressions] ')' > | primary '#' [module ':'] name '(' [expressions] ')' > > > Here's append/2 using abstract patterns. > > #empty() -> []. > #pair(H,T) -> [H|T]. > #head(H) -> [H|_]. > #tail(T) -> [_|T]. > > append1(#empty(), Y) -> Y; > append1(#pair(H,T), Y) -> #pair(H,append1(T,Y)). > > append2(#empty(), Y) -> Y; > append2(#head(H)=#tail(T), Y) -> #pair(H,append2(T,Y)). > > What does this mean? A pattern definition basically defines three > functions: a function to use for composition, a function to use for > decomposition, and a function to use for update. For the sake of > exposition, let's name the composition function for #x/n '#x'/n, the > decomposition function 'n=x'/1, and the update function '!x'/n+1. > > '#empty'() -> []. % composition function > '0=empty'([]) -> {}. % decomposition function > '!empty'([]) -> []. % update function > > '#pair'(H,T) -> [H|T]. > '2=pair'([H|T]) -> {H,T}. > '!pair'([_|_], H,T) -> [H|T]. > > '#head'(H) -> error(). % useless composition function > '1=head'([H|_]) -> H. > '!head([_|T], H) -> [H|T]. > > '#tail'(T) -> error(). % useless composition function > '1=tail'([_|T]) -> T. > '!tail'([H|_], T) -> [H|T]. > > append1(X, Y) when {} = '0=empty'(X) -> Y; > append1(X, Y) when {H,T} = '2=pair'(X) -> > '#pair'(H, append1(T,Y)). > > append2(X, Y) when {} = '0=empty'(X) -> Y; > append2(X, Y) when H = '1=head'(X), T = '1=tail'(Y) -> > '#pair'(H, append2(T,Y)). > > After inline expansion, these two definitions would be identical to each > other and to the usual definition. > > Suppose we are given a pattern definition > > #p(P11,...,P1n) when G1 -> Q1; > ... > #p(Pk1,...,Pkn) when Gk -> Qk. > > The composition function is obtained very simply by turning #p into '#p'. > > The decomposition function basically switches the left and right sides: > > 'n=p'(Q1) when G1 -> {P11,...,P1n}; > ... > 'n=p'(Qk) when Gk -> {Pk1,...,Pkn}. > > However, for the sake of field selection notation, and for efficiency, > the translation is simplified when n=1: > > '1=p'(Q1) when G1 -> P11; > ... > '1=p'(Qk) when Gk -> Pk1. > > The update function has to copy the bits that aren't mentioned and > replace the bits that are. Define Q'i to be Qi with anonymous variables > replaced by new variables, Q"i and G"i to be Q'i and Gi with the > original named variables consistently replaced by new variables. Then > we get > > '!p'(Q"1,P11,...,P1n) when G"1 -> Q'1; > ... > '!p'(Q"k,Pk1,...,Pkn) when G"k -> Q'k. > > All of these translations have to make sense. In particular: > 1. every variable used in a guard must be defined in both the > argument patterns and the replacement pattern corresponding. > 2a. If the composition function is to be usable, Qi must be fully > determined by Pi1...Pin and Gi, that is, have no variable, > anonymous or otherwise, that is not assigned a value by them. > 2b. On the other hand, if an update function is to be useful, there > should be some anonymous variables in Qi, or else why not > just use a composition function? > 3. Pij must be fully determined by Qi and Gi, that is, have no variable, > anonymous or otherwise, that is not assigned a value by them. > > This actually turns out to be too strict. There is no point in having > an abstract pattern that can only be used for composition; we already > have perfectly good functions for that. But there is some sense in > having an abstract pattern that can only be used for decomposition. > Accordingly, if condition 2a is violated by the ith clause, that clause > of the composition function becomes > > '#p'(Pi1,...,Pin) when Gi -> error(...) > > When an abstract pattern is invoked as part of a pattern, > > #[m:]p(P1,...,Pn) = E > > it is as if > > {P1,...,Pn} = [m:]'n=p'(E) > > were invoked instead, if n~=1, or as if > > P1 = [m:]'1=p'(E) > > were invoked, if n=1. Since abstract patterns are state independent and > have no side effects, it doesn't matter whether the translation > preserves left to right order or not; suffice it that pattern match > translation can preserve left to right order if we want. If #p/1 is an > abstract pattern, it may also be invoked as a field reference: > > E0#p > > is as if > > '1=p'(E0) > > had appeared instead. This applies to guard expressions as well as > general expressions. Note that E#p is different from #p(E). > > When an abstract pattern is invoked as part of an expression, > > #[m:]p(E1,...,En) > > it is as if > > [m:]'#p'(E1,...,En) > > were invoked instead. This clearly preserves the order and embedding of > expressions, so left to right execution order is not at all disturbed. > > When an abstract pattern is invoked for update, > > V = E0#[m:]p(E1,...,En) > > it is as if > > V = [m:]'!p'(E0, E1,...,En) > > were invoked instead. The only way this could perturb left to right > ordering is if the module prefix involved an expression other than a > variable or atom, and in that case the translation > > (ET = E0, V = m:'!p'(ET, E1, ..., En) > > can be used (assuming that Erlang does or will allow arbitrary primaries > as module prefixes) where ET is a new variable. The preservation of > left to right order is why the `base datum' argument of an update > function is the first rather than the last. > > There is one further condition. At the moment, if P is any pattern, and > P = P makes sense, (mainly, P contains no unbound variables), we expect > it to be true. But consider > > #p(1) -> []; > #p(2) -> []. > > Y = #p(2), #p(2) = Y > > will fail, because it turns into > > '#p'(1) -> []; '#p'(2) -> []. > '1=p'([]) -> 1; '1=p'([]) -> 2. > '!p'([],1) -> []; '!p'([],2) -> []. > > Y = '#p'(2), 2 = '1=p'(Y) > > The conditions we need are easy to state > 4. There does not exist any term T such that > Qi = T, Gi ==> true > Qj = T, Gj ==> true > i ~= j. > 5. There do not exist any terms T1,...,Tn such that > Pi1 = T1, ..., Pin = Tn, Gi ==> true > Pj1 = T1, ..., Pjn = Tn, Gj ==> true > i ~= j > but are less easy to check. The example clearly violates condition 4. > The difficulty of checking these conditions (a decision procedure for > arithmetic appears to be required) would at first sight appear to be a > problem, but in fact there are good reasons not to impose them, > > Now let's look at an example. > > ---------------------------------------------------------------- > Queue package example. > > We'll implement queues twice. > > -module(queue). > -export([#empty/0,#nonempty/1,push/2,pop/1]). > > #empty() -> []. > > #nonempty() -> [_|_]. % violates condition 2 > > push(Q, X) -> append(Q, [X]). > > pop([X|Q]) -> {X,Q}. > > %end. > > > -module(queue). > -export([#empty/0,#nonempty/1,push/2,pop/2]). > > #empty() -> {[],[]}. > > #nonempty() -> {[_|_],_}; % violates condition 2 > #nonempty() -> {[],[_|_]}. % violates condition 2 > > push({L,R}, X) -> {L,[X|R]}. > > pop({[X|L],R}) -> {X,{L,R}}; > pop({[],R}) -> [X|L] = reverse(R), {X,L}. > > %end. > > > -module(bfs). > -export(bfs/1). > -import(problem, [solved/1,children/1]). > -import(queue, [#empty/0,#nonempty/1,push/2,pop/1]). > > bfs(Start) -> > loop(push(#empty(), Start)). > > loop(#empty()) -> undefined; > loop(Q = #nonempty()) -> > {X,P} = top(Q), > case solved(X) of > true -> X; > false -> loop(pushall(P, children(X))) > end. > > pushall(Q, []) -> Q; > pushall(Q, [H|T]) -> pushall(push(Q,H), T). > > %end. > > > Here's the translation of the bfs module: > > -module(bfs). > -export(bfs/1). > > bfs(Start) -> > loop(queue:push(queue:'#empty'(), Start)). > > loop(Q) when {} = queue:'0=empty'(Q) -> > undefined; > loop(Q) when {} = queue:'0=nonempty'(Q) -> > {X,P} = queue:pop(Q), > case problem:solved(X) of > true -> X; > false -> loop(pushall(P, problem:children(X))) > end. > > pushall(Q, []) -> Q; > pushall(Q, [H|T]) -> pushall(queue:push(Q,H), T). > > %end. > > I have argued elsewhere that there should be two directives > > -use_early(module, [used functors]). > -use_late(module, [used functors]). > > which indicate that specified functors from a specified module are used, > the former indicating early binding, neither of them indicating that a > name is imported into the local scope. One reason for that was to > capture the good aspect of the preprocessor, which is precisely early > binding. But note that if we used the preprocessor to hide the > implementation of queues from the programmer while revealing it to the > compiler, we would have to use early binding, while with abstract > patterns, that's an independent choice. The bfs module can use #empty() > and #nonempty() as patterns without requiring early binding > > Note that replacing one version of the queue module by another while > bfs/1 was running would not be a good idea. This seems to be quite > typical, and I do not understand how Erlang avoids serious trouble. The > problem is that once the bfs/1 function has received a data structure > from the queue module, it depends on the queue module still accepting > the same data structure, so the process running bfs/1 depends on the > queue module even when it is not calling a function from that module. > There really needs to be some sort of locking facility so that bfs/1 > could be written > > bfs(start) -> > with_module_lock(queue, > loop(push(#empty(), Start))). > > However, if we are aware that there are long-lived processes that have > data structures of the old form that need to be supported for a while, > we might choose to write a queue module that supports both forms, while > preferring the new one, and it is for this reason that abstract patterns > may have more than one clause. (Although the second version of the > queue modules needs this anyway.) Here goes: > > -module(queue). > -export([#empty/0,#nonempty/1,push/2,pop/1]). > > #empty() -> {[],[]}; > #empty() -> []. % violates condition 5 > > #nonempty() -> {[_|_],_}; > #nonempty() -> {[],[_|_]}; > #nonempty() -> [_|_]. % violates condition 5 > > push({L,R}, X) -> {L,[X|R]}; > push(Q, X) -> append(Q, [X]). > > pop({[X|L],R}) -> {X,{L,R}}; > pop({[],R}) -> [X|L] = reverse(R), {X,L}; > pop([X|Q]) -> {X,Q}. > > %end. > > Try doing that with macros! > > Of course, macros provide early binding and inlining in one easy step, > which may (but need not) be good for efficiency. If an abstract pattern > is defined in the module that uses it, or if -use_early is defined, then > early binding occurs, and inlining is a possibility. The option of > inlining may be better than the certainty of inlining. Why? > > The first, and perhaps most obvious, reason is that abstract patterns > are named code forms with well defined invocation and contents, just > like functions. The fact that they can be used without requiring > inlining is good news for debuggers and interpreters, not to mention > test coverage analysers and profilers. > > The second is that inlining doesn't always help efficiency. There's no > point in executing 10% fewer instructions if, thanks to cache effects, > it takes 20% longer to do so. Back in the late 80s at Quintus, a > certain competitor claimed that their native-code Prolog system > generated code that ran twice as fast as ours. So it did, on naive > reverse. On a two-page program (which didn't fit into the 68020's > on-chip instruction cache), it did no better than our threaded-code > system. On a real program, it was twice as slow. I have heard that the > same phenomenon occurred with BEAM -vs- JAM. Inlining can have similar > effects, though less severe. > > One extension to Erlang would make it easier to inline abstract > patterns, and that is disjunctive guards. Currently, we have > > guard ::= ... '(' guard ')' > > replace that by > > guard ::= ... '(' guard {'|' guard}... ')' > > with the obvious semantics. This would be useful anyway. > > ---------------------------------------------------------------- > What's wrong with records? > > Records tangle up several things: > 1 the possibility of naming a pattern > 2 field and update notation. > 3 keyword and default arguments > 4 a very specific data structure > 5 a global name space > 6 the possibility of unchecked conflicting definitions in that namespace > 7 a requirement to use the preprocessor to get weak abstraction > 8 syntax that includes what LOOK like pattern matches but aren't. > > Some of these are good (1, 2, 3), some of them are less good (4), some > of them are bad (5 and 8) and some of them are very bad (6 and 7). > Pattern abstraction provides (1 and 2) without any of the others. > > What's wrong with (4)? First, it means that records actually give us no > abstraction at all; in the Erlang Standard specification, to be a record > of type T is precisely to be a tuple of a particular arity whose first > element is the atom T. Second, if we want to give a name to some other > structure, we are sunk, as records buy us nothing. Here is a realistic > example. Suppose we want to manipulate timestamps. For compatibility > with current Erlang, we might want these timestamps to contain embedded > date and time values. So > > #timestamp() -> {_, _}. > #timestamp(DT,TM) -> {DT, TM}. > #timestamp(Y,M,D,H,I,S) -> {{Y,M,D},{H,I,S}}. > > #time_date(DT) -> {DT,_}. > #time_date(Y,M,D) -> {{Y,M,D},_}. > > #time_time(TM) -> {_,TM}. > #time_time(H,I,S) -> {_,{H,I,S}}. > > #time_year(Y) -> {{Y,_,_},_}. > #time_month(M) -> {{_,M,_},_}. > #time_day(D) -> {{_,_,D},_}. > #time_hour(H) -> {_,{H,_,_}}. > #time_minute(I) -> {_,{_,I,_}}. > #time_second(S) -> {_,{_,_,S}}. > > Eventually, we purge our code of explicit references to the patterns, > and can switch to a more space-efficient representation: > > #timestamp() -> {_,_,_,_,_,_}. > #timestamp({Y,M,D},{H,I,S}}) -> {Y,M,D,H,I,S}. > #timestamp(Y,M,D,H,I,S) -> {Y,M,D,H,I,S}. > > #time_date({Y,M,D}) -> {Y,M,D,_,_,_}. > #time_date(Y, M, D) -> {Y,M,D,_,_,_}. > > #time_time({H,I,S}) -> {_,_,_,H,I,S}. > #time_time(H, I, S) -> {_,_,_,H,I,S}. > > #time_year(Y) -> {Y,_,_,_,_,_}. > #time_month(M) -> {_,M,_,_,_,_}. > #time_day(D) -> {_,_,D,_,_,_}. > #time_hour(H) -> {_,_,_,H,_,_}. > #time_minute(I) -> {_,_,_,_,I,_}. > #time_second(S) -> {_,_,_,_,_,S}. > > What do we have here? A change of representation. What is it that > records do not allow you to vary? The representation (except within > very narrow limits). > > Just to resume a topic that may not have been clear before, here are the > functions we get for the first of these definition sets. > > '#timestamp'() -> error(). > '0=timestamp'({_,_}) -> {}. > '!timestamp'({X1,X2}) -> {X1,X2}. > > '#timestamp'(DT, TM) -> {DT, TM}. > '2=timestamp'({DT,TM}) -> {DT, TM}. > '!timestamp'({X1,X2}, DT, TM) -> {DT,TM}. > > '#timestamp'(Y,M,D,H,I,S) -> {{Y,M,D},{H,I,S}}. > '6=timestamp'({{Y,M,D},{H,I,S}}) -> {Y,M,D,H,I,S}. > '!timestamp'({{X1,X2,X3},{X4,X5,X6}},Y,D,M,H,I,S) -> > {{Y,M,D},{H,I,S}}. > > '#time_date'(DT) -> error(). > '1=time_date'({DT,_}) -> DT. > '!time_date'({X2,X1}, DT) -> {DT,X1}. > > '#time_date'(Y,M,D) -> {{Y,M,D},_}. > '3=time_date'({{Y,M,D},_}) -> {Y,M,D}. > '!time_date'({X2,X1}, Y, M, D) -> {{Y,M,D},X1}. > > '#time_time'(TM) -> error(). > '1=time_time'({_,TM}) -> TM. > '!time_time'({X1,X2}, TM) -> {X1,TM}. > > #time_time(H,I,S) -> error(). > '3=time_time'({_,{H,I,S}}) -> {H,I,S}. > '!time_time'({X1,X2}, H, I, S) -> {X1,{H,I,S}}. > > '#time_year'(Y) -> error(). > '1=time_year'({{Y,_,_},_}) -> Y. > '!time_year'({X4,X1,X2},X3}) -> {{Y,X1,X2},X3}. > > '#time_month'(M) -> error(). > '1=time_month'({{_,M,_},_}) -> M. > '!time_month'({X1,X4,X2},X3}, M) -> {{X1,M,X2},X3}. > > '#time_day'(D) -> error(). > '1=time_day'({{_,_,D},_}) -> D. > '!time_day'({X1,X2,X4},X3}, D) -> {{X1,X2,D},X3}. > > '#time_hour'(H) -> error(). > '1=time_hour'({_,{H,_,_}}) -> H. > '!time_hour'({X1,{X4,X2,X3}}, H) -> {X1,{H,X2,X3}}. > > '#time_minute'(I) -> error(). > '1=time_minute'({_,{_,I,_}}) -> I. > '!time_minute'({X1,{X2,X4,X3}}, I) -> {X1,{X2,I,X3}}. > > '#time_second'(S) -> error(). > '1=time_second'({_,{_,_,S}}) -> S. > '!time_second'({X1,{X2,X3,X4}}, S) -> {X1,{X2,X3,S}}. > > So if, for example, we wanted to refer to noon today, or to find what > year it is, we could write > > Noon_Today = timestamp:now()#time_time(12,0,0), > This_Year = timestamp:now()#time_year > > and these would work whether a timestamp was stored as one tuple or > three. The -record approach cannot be used with the three tuple > version. (It can't be used with the one tuple version either, because > there must be an atom serving as a tag, and it must be the first element > of the tuple, and it must be the same as the record name.) > > What about keyword and default arguments (3)? Are they not a benefit of > using records? Yes, they are. But they should be available for all > functions and abstract patterns, not just records. Perhaps it is unfair > to say ``ask an Ada programmer'', because Ada doesn't use data the way > Erlang does. But Ada programs do have lots of procedure and function > calls, just as Erlang does, and Erlang functions need more arguments > than Ada functions, for the same reasons as Prolog, so need keyword and > default arguments more than Ada does. I intend that abstract patterns > should use whatever method is used to provide that feature for general > functions. > > Do records really imply a global namespace? Yes, because the record > name appears inside the record. Consider: > > -module(a). > -record(r, {X,Y,Z}). > ... > f(..R..) when record(R, r) -> > > -module(b). > -record(r, {X,Y}). > g(R) when record(R, r) -> f(R). > ... g(#r{1,2}) ... > > It is not clear exactly what the record/2 guard test should do. One > manual says "This test checks that R is a tuple of arity N+1, where N is > the number of fields in the record, and the first element in the tuple > is the" atom naming the record. This means that g/1 WILL believe that > record(R, r) is true, but f/1 will NOT. That does mean that f/1 will not > be tricked into working with something that doesn't match its idea of > what an `r' record looks like, but programmers will find it very > confusing that record(R,r) can succeed in one module and fail in another. > It is also a nuisance that we cannot tell whether something "is a record > of type r" without having a -record declaration in scope. That doesn't > apply to any other guard test. > > The real problem comes when a and b agree on the arity of r but disagree > on the argument order or interpretation. Consider again, > > -module(a). > -record(r, {X,Y,Z}). > ... > f(...#r(X,Y,Z)...) -> ... > > -module(b). > -record(r, {Z,Y,X}). > ... > f(...#r(Z,Y,X)...) > > Either a global namespace for records is enforced (so that the record/2 > guard test works consistently), or serious confusion may result. The > snag here is that a record name ought to be `owned' by some module, but > in fact it is `owned' by a preprocessor file. > > How do pattern abstractions address this problem? In part, it must be > admitted, they don't. They are weak abstractions; there is no defence > against forgery, and little defence against accident other than adding a > tag, just like records. The advantage comes from the fact that an > abstract pattern is clearly owned by a specific module; there is one > declaration, not multiple copies of a declaration. Abstract pattern > names are module qualified, just like other function names. > > There is something that could be done that would make accident unlikely > and forgery slightly harder. Records differ from tuples in that they > are tagged. The tags cannot be module-specific, because the same > declaration may be copied into many modules, with no clue as to which is > the owner. All we do is take the idea of tagging, and bend the existing > module-specific literal syntax (like ?VERSION and ?MODULE) a little bit. > The directive > > -unique(name). > > would mean that at load time a new ref() would be created and bound to > name, in such a way that the name can be recovered from the ref() for > debugging purposes, and at compile time each occurrence of ?name would > refer to that ref(). (This is like the classic Lisp hack of using a > unique cons cell or function closure as a tag.) Then we could write > > -unique(ts). > > #timestamp() -> {?ts,_, _}. > #timestamp(DT,TM) -> {?ts,DT, TM}. > #timestamp(Y,M,D,H,I,S) -> {?ts,{Y,M,D},{H,I,S}}. > > #time_date(DT) -> {?ts,DT,_}. > #time_date(Y,M,D) -> {?ts,{Y,M,D},_}. > > #time_time(TM) -> {?ts,_,TM}. > #time_time(H,I,S) -> {?ts,_,{H,I,S}}. > > #time_year(Y) -> {?ts,{Y,_,_},_}. > #time_month(M) -> {?ts,{_,M,_},_}. > #time_day(D) -> {?ts,{_,_,D},_}. > #time_hour(H) -> {?ts,_,{H,_,_}}. > #time_minute(I) -> {?ts,_,{_,I,_}}. > #time_second(S) -> {?ts,_,{_,_,S}}. > > This is admittedly clumsy, but it's the idea I want to push, not the > syntax, which is at least local to the owning module. This looks a bit > like the preprocessor, but it only requires recognising ? as a > special form. If we left the question mark off (and the binding to a > ref()) we would have the same insecure approach as records, without the > requirement of a fixed location for the tag. > > Thanks to preprocessor use, that insecurity is real. The really nasty > thing happens when module a gets its record declaration from foo.hrl, > module a is compiled and loaded, foo.hrl is changed, and another module > including (the revised version of) foo.hrl is compiled and loaded. We > have a dependency between module a and foo.hrl which is not noticed; > partly because foo.hrl is not a module and is not, as such, loaded, and > partly because the dependency exists even while the code in foo.hrl is > not running. > > So we are left with only one thing that abstract patterns cannot do as > well as records or better, than that is keyword and default parameters. > At one time it was expected that records would become new types; this > seems to have been dropped from the current Erlang Standard > specification (0.6); I surmise because of the difficulty of establishing > an `owner'. > > There is one more thing that abstract patterns can do that records as > currently defined in Erlang cannot do, and that is enforce type > constraints on components. Consider triangles. We'd like a triangle to > be represented by a `record' containing three floats. Using record > notation, all we can do is write > > -record(triangle{A,B,C}). > > and hope. Using abstract pattern notation, we can write > > #triangle(A,B,C) when float(A), float(B), float(C) -> {A,t,B,C}. > > and this will enforce the type constraints on the components. Here is a > sample use of this pattern, to see whether a value of this type is a > plausible triangle. > > plausible(#triangle(A,B,C)) > when 0 < A, A <= B+C, > 0 < B, B <= C+A, > 0 < C, C <= A+B > -> true; > plausible(_) -> false. > > After translation and inline expansion, plausible/1 becomes > > plausible({A,t,B,C}) % check form > when float(A), float(B), float(C), % check types > 0 < A, A <= B+C, > 0 < B, B <= C+A, > 0 < C, C <= A+B > -> true; > plausible(_) -> false. > > This ability to propagate type information/checking from the declaration > to the uses, if the programmer wants it, is an important safety feature > that is completely missing from Erlang records, and is obtained without > any new runtime machinery. Note that an Erlang compiler can easily > deduce from the use of A, B, C that they must be some kind of number, > but not which kind, not without interprocedural data flow analysis. > Even without inlining, we get the runtime type checking we choose in the > declaration, which has to be helpful if we want to build large systems. > > The End. > > The abstract pattern notation neatly replaces both the record > declarations and the use of the preprocessor. > > Records let you say > > L2 = L#log{blocked_by = none, status = ok} > > which is arguably prettier than > > L2 = L#log_blocked_by(none)#log_status(ok) > > but not hugely so. One could argue that the abstract pattern > version has the merit of not containing a manifestly false > pattern match 'status = ok'. > > Records automatically provide you with a full set of record.field > forms; abstract patterns for them have to be separately declared. > On the other hand, records *force* you to accept a full set of > record.field forms even if you want some of them blocked, and it > is not at all clear how import/export of #record.field forms would > be controlled. > > Records permit patterns like > > #log{status == S, users = N} = L > > which is arguably prettier than > > #log_status(S) = #log_users(N) = L > > but again, the latter never contains manifestly absurd matches. > > Dynamic Patterns. > > The parallel between abstract patterns and functions can be stretched a > little further. In effect, we can regard a value of type > (T1,...,Tn) => T0 > [where => is the pattern arrow in distinction to the function arrow ->] as > a record > ( b : (T1,...,Tn) -> T0 % building > u : (T0,T1,...,Tn) -> T0 % updating > d : T0 -> (T1,...,Tn) % decomposing > ) > and > X = #p(E1,...,En) ==> X = p.b(E1,...,En) > X = E0#p(E1,...,En) ==> X = p.u(E0,E1,...,En) > #p(P1,...,Pn) = E ==> {P1,...,Pn} = p.d(E) > Since a triple of functions can be passed as a value, why not allow a > pattern to be passed as a value? Let's put this in Erlang terms. > > Define > #E0(E1,...,En) > where E0 is not an atom or a module:atom pair to be > #apply(E0, [E1,...,En]) > Define > #apply(Mod,E0,EL) > to be > #apply({Mod,E0}, EL) > Now we have to define the use of #apply/2. > > X = #apply(MF,L) > where MF = {M,F}, L = [T1,...,Tn}, and M, F are atoms > reduces to X = #M:F(T1,...,Tn), i.e. X = M:'#F'(T1,...,Tn). > where MF is the result of (fun #F/N) executed statically within > module M, L = [T1,...,Tn], and N = n, > reduces to X = #M:F(T1,...,Tn) > > X = E0#apply(MF,L) > where MF = {M,F}, L = {T1,...,Tn} and M, F are atoms > reduces to X = E0#M:F(T1,...,Tn) i.e. X = M:'!F'(E0,T1,...,Tn) > where MF is the result of (fun #F/N) executed statically within > module M, L = [T1,...,Tn], and N = n, > reduces to X = Eo#M:F(T1,...,Tn). > > #apply(MF, [P1,...,Pn]) = E > where MF is statically a GuardExpression whose value is dynamically > {M,F} for M and F atoms, and [P1,...,Pn] is statically a list > of Patterns, > reduces to #M:F(P1,...,Pn) = E, i.e. {P1,..,Pn} = M:'n=F'(E). > where MF is statically a GuardExpression whose value is dynamically > the result of (fun #F/N) executed statically within a module M, > [P1,...,Pn] is statically a list of Patterns, and N = n, > reduces to #M:F(P1,...,Pn) = E. > > Now we can do things like this: > > proj(P, []) -> []; > proj(P, [#P(X)|Xs[) -> [X|proj(P,Xs)]. > > #unit_list(X) -> [X]. > #unit_tuple(X) -> {X}. > > ... proj(fun #unit_list/1, L), ... > ... proj(fun #unit_tuple/1, LT), ... > > By bending explicit fun syntax a little bit, we can even get anonymous > patterns: > fun #( Pattern... ) when Guard -> Pattern > ; #( Pattern... ) when Guard -> Pattern ... > end > e.g. > fun #(X) -> [X|_] end > is an anonymous `hd' pattern. (The syntax here is based on two rules: > to get pattern syntax from function syntax, put # in front of the > [Module:]Name, and to get explicit fun syntax, put `fun' `end' around > the clauses and delete the function Name.) It's not that I think > anonymous patterns are wildly useful; the point is that if they weren't > at least thinkable the parallels between patterns and functions would be > sploit, to the detriment of our ability to reason correctly about them. > > Try doing that with records! > > As a matter of fact, dynamic patterns do something for us that isn't > easy to get any other way. Look at prof/2 again. Is there any > nonsyntactic difference between > > proj(P, []) -> []; > proj(P, [#P(X)|Xs]) -> [X|proj(P, Xs)]. > > and > > map(F, []) -> []; > map(F, [X|Xs]) -> [F(X)|map(F, Xs)]. > > or is it just a piece of `cuteness' that lets you put the function call > on the `wrong' side? > > Yes, there is a difference. The function F in map/2 may do anything at > all; it may have side effects, it may allocate arbitrarily large amounts > of storage, it may run for huge amounts of time. The pattern P in > proj/2 must be an abstraction of a pattern-and-guard: it may not send > or receive messages, have any other side effects, allocate huge amounts > of storage, or take unbounded amounts of time. It is forced to be well > behaved in ways that an arbitary function parameter is not. Indeed, we > are sure that the value X it returns in proj/2 is part of the term it > matches, so it really is a projection function. If we want to reason > about the effects of a code fragment, proj/2 is significantly easier to > reason about than map/2. This means that anonymous patterns do have a > use: > > proj(fun #(X) -> {X,_,_} end, L) > > is trivially well-behaved, whereas > > map(fun ({X,_,_}) -> X end, L) > > requires more analysis to see its harmlessness. (Of course, checking > higher order functions is never entirely trivial, and it is something of > a pity that they were added to Erlang so hastily. Topic for another > working paper.) > > When you've invented a language construct, a good sign that you are onto > something worthwhile is that applications come faster than you have time > to write them down. When I wrote the stuff about dynamic abstract > patterns, I didn't have an application in mind. But I suddently realised > that there was a proposal I thought of last year which had been > languishing > because there was no safe way to do it. > > Erlang processes are vulnerable to a denial-of-service attack where a > malicious or erroneous process repeatedly sends "junk mail". The Erlang > documentation recommends that most or all 'receive' commands should > include a wildcard case to discard junk mail, but that has the > disadvantage > that it won't discard junk mail until the process actually executes a > receive. Junk mail can pile up while a process is suspended. If nothing > else, it causes the recipient of the junk mail to pay (in processing and > garbage collection time) to inspect it. > > Last year I came up with the idea of a 'message filter'. > > set_process_filter(fun (Msg) -> ... true | false end) > > would mean that whenever a (local) process send a message to this one, > the message filter function would run IN THE SENDER'S THREAD to see if > the message was ok. If it returned 'false', the message would be > discarded, otherwise it would be retained. > > The problem with that is that it makes the sender vulnerable to Trojan > horses; the message filter function could do absolutely anything while > masquerading as the sender. What I needed was a way of declaring and > enforcing that the message filter function would execute in bounded time > with no side effects. > > Does that sound familiar? It's basically an abstract pattern. > > So here's the new proposal. > > set_process_filter(fun #() when Guard -> Pattern end) > > If the argument is a pattern expression of arity 0, then > when a message is sent to this process, the pattern will > be executed in the sender's thread and if it matches the > message will be sent and if it fails the message will be > discarded. > > set_process_filter(fun #(Result) when Guard -> Pattern end) > > If the argument is a pattern expression of arity 1, then > when a message is sent to this process, the pattern will > be executed in the sender's thread, and if it matches, > the Result will be sent, and if it fails, the message > will be discarded. > > Of course these forms are only illustrative; there could be any number > of clauses and fun #F/0 or fun #F/1 could be used instead. The use of > set_process_filter/1 would be to allow simple protocol conversions. > > Whether this feature is as useful as I think is debatable; Tobbe > argues that the best idea is to conceal processes inside their creating > modules, and I think he's probably right about that. The point is that > dynamic functions whose cost is certainly bounded are a useful thing to > have, and they fall out quite naturally from trying to take abstract > patterns seriously. > > From joe@REDACTED Tue Sep 23 15:04:42 2003 From: joe@REDACTED (Joe Armstrong) Date: Tue, 23 Sep 2003 15:04:42 +0200 (CEST) Subject: soure->source Xformer In-Reply-To: Message-ID: On Tue, 23 Sep 2003, Richard Carlsson wrote: > > On Tue, 23 Sep 2003, Joe Armstrong wrote: > > > Has anybody (Luke?, Robert?) got a source->source Erlang transformer > > that expand out > > > > - records > > - funs > > - list-comprehensions > > - if/case/receive > > > > This is prettry similar to erl_lint + sys_pre_expand only brought > > up-to-date for list-comprehensions and records. > > sys_pre_expand already *does* expand away records and list > comprehensions (do "c(foo, ['E'])." and look at the "foo.E" file). Sorry - I'd forgotten aabout the records - but the expansion of list comprehensions is missing ... > > Adding a pass to expand ifs to normal cases should be simple (there used > to be a template parse transform file somewhere - under stdlib I think - > but I can't find it in the current distribution). Or just hack > sys_pre_expand to do it for you - it should not make any difference > if it is done there or later (well, the debugger could be confused). Yup - done this before :-) > Funs should _not_ be "expanded" however, as long as you're still on this > level - it's a *big* mistake to expose the actual implementation of > closures until you get to the really low level code. This where I am of two minds. One part of me says implement funs by lambda-lifting and transforming into regular first-order code (and yes I know you have to "cheat" with the odd funny atom name :-) The other part says make "proper" closures (internally) - both approaches have advantages and disadvantages. IMHO the difficult bit in an implementation is the layering - what goes into which layer.... > /Richard > > > Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) > E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ > "Having users is like optimization: the wise course is to delay it." > -- Paul Graham > From vlad_dumitrescu@REDACTED Tue Sep 23 15:11:56 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Tue, 23 Sep 2003 15:11:56 +0200 Subject: c:m() output to variable References: <001201c381a7$4f363520$1e00a8c0@design> Message-ID: >Does anyone know if there is a way to store the output of c:m() in a variable? >L = c:m(). No, you can't but the same information can be retrieved by running code:all_loaded() or better lists:sort(code:all_loaded()) c:m() just formats this list. regards, Vlad From richardc@REDACTED Tue Sep 23 15:16:39 2003 From: richardc@REDACTED (Richard Carlsson) Date: Tue, 23 Sep 2003 15:16:39 +0200 (MET DST) Subject: soure->source Xformer In-Reply-To: References: Message-ID: On Tue, 23 Sep 2003, Joe Armstrong wrote: > > sys_pre_expand already *does* expand away records and list > > comprehensions (do "c(foo, ['E'])." and look at the "foo.E" file). > > Sorry - I'd forgotten aabout the records - but the expansion of list > comprehensions is missing ... You're right; sorry - list comprehensions are dealt with in the 'v3_core' module. (And it is messy because it is expanding and translating at the same time. It is a much nicer approach to put every nontrivial transformation in a separate pass, even if it means that you traverse stuff more than once.) /Richard Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.) E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/ "Having users is like optimization: the wise course is to delay it." -- Paul Graham From crav@REDACTED Tue Sep 23 11:03:54 2003 From: crav@REDACTED (=?iso-8859-1?Q?Carlos_Rodr=EDguez_Alcal=E1_Villagra?=) Date: Tue, 23 Sep 2003 10:03:54 +0100 Subject: erlang ---anyone Message-ID: <004101c381b1$9e308400$6600a8c0@carlos> Would the Erlang's Megaco Implementation work with other Megaco implementations? How standard is it? -------------- next part -------------- An HTML attachment was scrubbed... URL: From crav@REDACTED Tue Sep 23 11:03:58 2003 From: crav@REDACTED (=?iso-8859-1?Q?Carlos_Rodr=EDguez_Alcal=E1_Villagra?=) Date: Tue, 23 Sep 2003 10:03:58 +0100 Subject: erlang and whereever Message-ID: <004501c381b1$9f9ae970$6600a8c0@carlos> I would like to know if anyone has tried the Erlang's Megaco Libraries with the MAX TNT version 10.1.0 Gateway from Lucent. Or, with any other Gateway of Lucent? -------------- next part -------------- An HTML attachment was scrubbed... URL: From sagan@REDACTED Tue Sep 23 16:23:39 2003 From: sagan@REDACTED (sagan) Date: Tue, 23 Sep 2003 09:23:39 -0500 (CDT) Subject: Large number of nodes Message-ID: Hi all, I have a question regarding a project I am starting to design: - 2 Servers (Replicating Mnesia and accessing back-end DBs) - 2000 clients (Periodically quering the servers for data) I am concerned about having all nodes connected and large amount of network chattyness while the majority of machines are idle. Only rarely, a server will attempt to contact a client (based on a previous app registration) and notify it for some event has occured. I think the following is safe: - Start all client nodes using -connect_all false - Start server nodes as usual - All nodes share the same .erlang.cookie - When a client queries a server, use erlang:disconnect_node(Node) to cleanup the connection. After simple testing it seems to be okay, but tough for me to recreate an environment of 2000 nodes distributed over a national WAN. I ran the following test: (S=Server C=Client) Start S1 Start S2 S1 -> Ping S1 (Now S1 and S2 know about each other) Start C1 with -connect_all false C1 -> Ping S1 (C1 only knew about S1 and vice-versa, good) (S2 still only knew of S1) I was worried S2 would find out about C1, since S2 was not started with -connect_all false. Can anyone explain the algoritm/process for nodes establishing connections. Would using a hidden node for all clients be better? Thanks in advance... Sagan From erlang@REDACTED Tue Sep 23 17:30:28 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Tue, 23 Sep 2003 16:30:28 +0100 Subject: erlang ---anyone In-Reply-To: <004101c381b1$9e308400$6600a8c0@carlos> References: <004101c381b1$9e308400$6600a8c0@carlos> Message-ID: <3F706714.1020103@manderp.freeserve.co.uk> Hi Carlos, Short answer: Yes, and RFC 3525 standard (although I haven't used _every_ feature in megaco, so I'm not qualified to say so :-) Long answer: We used the OTP Megaco stack for acceptance tests here, and while I created the tests I did find one problem using topologyRequest, and another due to the ABNF having a comment which should really have been part of the ABNF grammar, but that was all. When we conducted the acceptance test, no issues were raised against OTP Megaco, and the test revealed numerous protocol issues with the third party stack implementation, delivered to us by a reputable protocol stack implementor for our internal use. So I confidently believe that the rest of OTP Megaco stack is very solidly compliant to the standard. The issues raised against OTP Megaco were quickly resolved by the OTP Team at Ericsson. I also am confident that any interoperability issues will be due to third-party stacks being non-compliant to the standard. Why are we not using Erlang/OTP Megaco for our product? The reason is entirely political, and not based on the superior technical merits of the Erlang/OTP Megaco stack. There is only one person in the company (me) who uses Erlang. Having produced a working prototype of the product mostly using Erlang whereas all the rest are still struggling to debug C++ code and still have not matched the performance of the prototype has caused some hurt pride. I'm not a better programmer, I'm just using a better tool :-) Pete. Carlos Rodr?guez Alcal? Villagra wrote: > > Would the Erlang's Megaco Implementation work with other Megaco > implementations? How standard is it? From luke@REDACTED Tue Sep 23 17:36:33 2003 From: luke@REDACTED (Luke Gorrie) Date: 23 Sep 2003 17:36:33 +0200 Subject: erlang ---anyone In-Reply-To: <3F706714.1020103@manderp.freeserve.co.uk> References: <004101c381b1$9e308400$6600a8c0@carlos> <3F706714.1020103@manderp.freeserve.co.uk> Message-ID: Peter-Henry Mander writes: > I'm not a better programmer, I'm just using a better tool :-) What an incredibly artificial distinction. :-) -Luke From cpressey@REDACTED Tue Sep 23 18:17:53 2003 From: cpressey@REDACTED (Chris Pressey) Date: Tue, 23 Sep 2003 09:17:53 -0700 Subject: new syntax - a provocation In-Reply-To: References: Message-ID: <20030923091753.21901e6e.cpressey@catseye.mine.nu> On Tue, 23 Sep 2003 10:42:46 +0200 (CEST) Joe Armstrong wrote: > 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. Creating a new language without those wrong things ever in it is IMHO an even better idea... especially when there are paying customers, and when you don't have to change the backend much, if at all... > Now a few comments: > [...] > 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. I like it, more or less - the mechanism is good, but I'm not sure whether the fun notation is desirable (why not just write them like normal functions and have them as lambdas "under the hood" - nested functions, perhaps?) - and, how easy would it be to work out the details for retaining state between hot code upgrades? > - Proper structs > > << junk the record stuff. thus has been discussed in previous > mails >> Yes. Either harmonize them with dicts, or disallow untagged tuples :) > - 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 >> Yes, but can you still ensure constant time operations on atoms? > - 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.>> Also, a process should always be able to tell the pid of the process that *really* sent the message. (Not just any old pid the sender felt like sticking in the message.) As for flooding, you could, in today's Erlang, write a 'safe_send' function that checks the receiver's buffer before sending, but that would impact performance negatively, I imagine. Also - what is the desired behaviour for when the receiver's buffer is full? Block, or discard? The syntax for sending might outgrow nice simple A ! B. > - 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. Hmmm... I did like the notion of adding state to the type system. Some research into how to create a type system that works well with messaging is probably warranted. > IMHO we need to modify Erlang to increase the isolation > properties. Erlang already has some of the best isolation properties of any language, though... the only way I can think to improve them (beyond what I've already mentioned) is to make locking easier. But locking is already easy! So do you have any other concrete ideas on what would need to be added/removed/fixed to make processes even better isolated? > The "make it slower" track has been ignored. For better or worse, speed does rule the industry. But I grant you that MIPS is not always the best "kind" of speed. "Speed" of maintenance is probably the critical thing in my mind. Consider: if you don't put the work into making the language implementation fast, programmers are going to write their own code in an optimized manner to compensate - making it much harder to maintain. > > 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) ...and design a new language :) -Chris From vlad_dumitrescu@REDACTED Tue Sep 23 20:40:26 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Tue, 23 Sep 2003 20:40:26 +0200 Subject: Large number of nodes References: Message-ID: > - 2 Servers (Replicating Mnesia and accessing back-end DBs) > - 2000 clients (Periodically quering the servers for data) ... > After simple testing it seems to be okay, but tough for me to recreate an > environment of 2000 nodes distributed over a national WAN. This is possibly a matter of taste, but in a situation like this I'd rather use regular sockets instead of Erlang distribution. Just a feeling :-) regards, Vlad From bparsia@REDACTED Tue Sep 23 20:43:56 2003 From: bparsia@REDACTED (Bijan Parsia) Date: Tue, 23 Sep 2003 14:43:56 -0400 (EDT) Subject: new syntax - a provocation In-Reply-To: Message-ID: On 23 Sep 2003, Mike Williams wrote: > The best way to "kill" a language is to make continuous additions. Bullets through the head, help. Counterexamples: Java, C++, Python, Perl > If people believe a language is in the process of change, they > won't use it. [snip] See the counterexamples. Cheers, Bijan Parsia. From thomasl_erlang@REDACTED Tue Sep 23 21:07:09 2003 From: thomasl_erlang@REDACTED (Thomas Lindgren) Date: Tue, 23 Sep 2003 12:07:09 -0700 (PDT) Subject: soure->source Xformer In-Reply-To: Message-ID: <20030923190709.34315.qmail@web41906.mail.yahoo.com> --- Joe Armstrong wrote: > [Richard]: > > Adding a pass to expand ifs to normal cases should > be simple (there used > > to be a template parse transform file somewhere - > under stdlib I think - > > but I can't find it in the current distribution). stdlib/examples/erl_id_trans.erl [Joe]: > One part of me says > implement funs > by lambda-lifting and transforming into regular > first-order code > (and yes I know you have to "cheat" with the odd > funny atom name :-) > The other part says make "proper" closures > (internally) - both > approaches have advantages and disadvantages. I seem to recall that older versions of the preprocessor transformed fun:s into tuples, which seems to be what you want. In my own current system, which is not a full compiler, the working representation is basically preprocessed code (-E) with a bit of postprocessing to get rid of some remaining nasty cases: - records have become tuples - funs are kept as (Code, [FreeVar]) - funs are added to exports (after mild massaging to make them exportable) - repeated variables are converted to explicit guard matching - modules are renamed (with indirect calls dynamically renaming the module to invoke List comprehensions should be removed at this point too, but currently are not. Doing so is fairly straightforward, so it's really just laziness. Unlike Core Erlang, it's still Erlang. But it's also easier to work with than full Erlang. (It should be said some of the above are motivated by the optimizations I do, rather than generic.) > IMHO the difficult bit in an implementation is the > layering - what goes into which layer.... Heh, yes. The basic approach, in my experience, has to be to first decide what you want to do with each intermediate language. On each level, some optimizations become natural while others become vile. Conversion between the languages gradually reduce to the chosen target format. Some zen is required to get this right. Best, Thomas __________________________________ Do you Yahoo!? Yahoo! SiteBuilder - Free, easy-to-use web site design software http://sitebuilder.yahoo.com From erlang@REDACTED Tue Sep 23 21:16:28 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Tue, 23 Sep 2003 20:16:28 +0100 Subject: erlang ---anyone In-Reply-To: References: <004101c381b1$9e308400$6600a8c0@carlos> <3F706714.1020103@manderp.freeserve.co.uk> Message-ID: <3F709C0C.2060906@manderp.freeserve.co.uk> Oh, I'm sure you mean to flatter me Luke! Let me rephrase: I'm no genius, but I can recognise the worth of a good programming language! Luke Gorrie wrote: > Peter-Henry Mander writes: > > >>I'm not a better programmer, I'm just using a better tool :-) > > > What an incredibly artificial distinction. :-) > > -Luke > > > From ok@REDACTED Wed Sep 24 06:38:57 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Wed, 24 Sep 2003 16:38:57 +1200 (NZST) Subject: YATT (Yet Another Typing Thread) Message-ID: <200309240438.h8O4cvqf042498@atlas.otago.ac.nz> Luke Gorrie wrote [that he likes the Common Lisp type system] Henry Baker had a paper (available somewhere on the net) on how it could have been better (better suited to inference). The really nasty thing about the Common Lisp type system is that (at least in certain compilation models) if you state that something has a certain type the compiler will believe you, and generate code that can crash or do insane things. Does CMUCL fix that in any way? From vlad_dumitrescu@REDACTED Wed Sep 24 09:22:32 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Wed, 24 Sep 2003 09:22:32 +0200 Subject: essential Erlang References: Message-ID: From: "Joe Armstrong" > 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. Hi, your mail, and some other discussions here, made me think of something that for me is rather revolutionary. If it happens to be something either impossible or obvious, I apologize for taking your time. Why not take this idea of separating the concerns to its limit? At the bottom there would be two parts: a "process engine" that should only know about spawning, killing and scheduling processes, and also about the communication between them. The other part would handle the interface with the outside world: memory management, IO, file systems, hardware. Possibly it isn't possible to implement the two efficiently without strong dependency, but the goal would be to have them as separate as possible. Now what would processes do? Run, of course. This would be inside a virtual machine (*) - but after the former separation, it seems to me that this VM could be (in principle) almost any VM. Even more, different processes could even run on different kind of VMs. Of course the most efficient would probably be to use the same one. But wouldn't it be cool to be able to run Java and .Net as Erlang processes (**) and in the long run convert all of those to Erlang? ;-) After describing this architecture, it begins to look like a OS kernel (I think) and I am pleased to notice that :-) In the future maybe this will be *the* OS... (*) In a general sense, even machine code can be seen as bytecode for a VM. (**) Not unmodified programs from today, but code that targets this OS. Is this only an utopia, or could there be something that will work in real life? There is a lot of OS research that targets this area, so it's possible this is already done or at least been looked at. What do you think? regards, Vlad From luke@REDACTED Wed Sep 24 10:38:15 2003 From: luke@REDACTED (Luke Gorrie) Date: 24 Sep 2003 10:38:15 +0200 Subject: YATT (Yet Another Typing Thread) In-Reply-To: <200309240438.h8O4cvqf042498@atlas.otago.ac.nz> References: <200309240438.h8O4cvqf042498@atlas.otago.ac.nz> Message-ID: "Richard A. O'Keefe" writes: > Luke Gorrie wrote > [that he likes the Common Lisp type system] On further thought though, it is not what I want in a "soft-typing" system for Erlang. It seems that the class of type errors that can be unambiguously detected in regular Erlang (or Common Lisp) code is pretty small. In general I'd estimate about 10% of my time is spent writing code that manipulates fairly complex data structures and is somewhat painful to get right. I'm quite interested in nifty (and simple and reliable) tools to make that code easier to write. I admit I have been waiting for someone else to say "hey, I tried and it works great!" before seriously looking in to those. (If the guys at work did a "cvs update" and found a static type checker and a bunch of funky-looking declarations around the codebase, I would be pelted with rotten fruit.) > Henry Baker had a paper (available somewhere on the net) > on how it could have been better (better suited to inference). "The Nimble Type Inferencer" I presume? Thanks for the tip, I'll give it a read. > The really nasty thing about the Common Lisp type system is > that (at least in certain compilation models) if you state that > something has a certain type the compiler will believe you, and > generate code that can crash or do insane things. > > Does CMUCL fix that in any way? Yes. In CMUCL type declarations are treated as assertions that must be tested, just like guards in Erlang. It then uses type-inference both to eliminate unnecessary type checks (like that adding two integers will produce an integer, or adding two numbers between 0 and 255 won't produce a bignum), and to generate fast type-specialised code. The Erlang compiler apparently does a bit of this already to run Wings fast, and I suppose it's really a compiler implementation issue at heart. NB: I've read on the CMUCL mailing list that their safety is not absolutely perfect, but I believe it's very thorough. It's also possible to explicitly disable type checking using the standard CL "turn off safety" declaration, giving you fast code that will crash horribly if it breaks promises about types. Cheers, Luke From joe@REDACTED Wed Sep 24 10:56:33 2003 From: joe@REDACTED (Joe Armstrong) Date: Wed, 24 Sep 2003 10:56:33 +0200 (CEST) Subject: new syntax - a provocation In-Reply-To: <20030923091753.21901e6e.cpressey@catseye.mine.nu> Message-ID: On Tue, 23 Sep 2003, Chris Pressey wrote: > > << 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 >> > > Yes, but can you still ensure constant time operations on atoms? There are two ways of doing this: Method 1 ======== This method assumes the atom table works like a cache and can be destroyed at any time. If it is destroyed then it is rebuilt the next time you refer to an atom. This method was suggest to me by Per Brand at Sics. Suppose an atom (on the stack or heap) can be in one of two forms: Originally like this: +---------------------+ | Atom1 | Mod | Index | +---------------------+ Atom1 is an "Atom1" tag - Mod and Index are just integer indices (not pointers). Now assume there is a global atom table (a hash table). The first time this atom is referred to, it is changed to +---------------------+ | Atom2 | Pointer | +---------------------+ ie just like things are today. Suppose now that the compiler generates code like this: pushAtom1 {atom1, Mod, Index} free-space (these are instructions for a 32-bit threaded machine) Then the first time this instruction is executed the net result is to change the instruction to: pushAtom2 {atom1, Mod, Index} {atom2, Pointer} thereafter the value in the atom table is used. To "garb" the atom table you do a few things: - junk the atom table - scan the code changing pushAtom2 instructions back to pushAtom1. - make a new empty hash table Every time you junk the atom table a new one will be automatically rebuilt the next time and atom is referenced. There are a few housekeeping details to think about - but the method seems sound Method2 ======= No global atom table. Atoms in any module are represented +---------------------+ | Atom1 | Mod | Index | +---------------------+ Comparison of atoms in the same module is done in unit time. Comparison of atoms in different modules involves a single string comparison when the the atom is pattern matched in an exported function call. If the comparison of +-----------------------+ X = | Atom1 | Mod1 | Index1 | +-----------------------+ and +-----------------------+ Y = | Atom1 | Mod2 | Index2 | +-----------------------+ succeeds then we can always interchange any use of X with Y or vice versa. Hopefully choosing the "correct" type for future processing with a module ... > > - 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.>> > > Also, a process should always be able to tell the pid of the process > that *really* sent the message. (Not just any old pid the sender felt > like sticking in the message.) > > As for flooding, you could, in today's Erlang, write a 'safe_send' > function that checks the receiver's buffer before sending, but that > would impact performance negatively, I imagine. Also - what is the > desired behaviour for when the receiver's buffer is full? Block, or > discard? The syntax for sending might outgrow nice simple A ! B. > > > - 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. > > Hmmm... I did like the notion of adding state to the type system. Some > research into how to create a type system that works well with messaging > is probably warranted. > > > IMHO we need to modify Erlang to increase the isolation > > properties. > > Erlang already has some of the best isolation properties of any > language, though... the only way I can think to improve them (beyond > what I've already mentioned) is to make locking easier. But locking is > already easy! So do you have any other concrete ideas on what would > need to be added/removed/fixed to make processes even better isolated? > Interesting - I'd *much* prefer a solution based on implicit contracts and no locking - locking distributed objects makes me shudder in horror .. Assume that there is an implicit contract between any pair of processes of the form. " I will not send you more than 500 messages/sec " and " I will not send you more than 10MB/sec " A process violating the sender side of a contract could be punished with an exit(Pid, youSentTooManyMessages). At the outer level of abstraction processes are black boxes. Their communication is regulated by contracts. Contracts can specify functional behaviour (types) and non-functional behaviour (example, I will reply within 10ms, I will send max 100 messages/hour). This is why I'd like to tightly integrate the UBF stuff into Erlang, and provide wrappers so that components can be written in any language. > > The "make it slower" track has been ignored. > > For better or worse, speed does rule the industry. I disagree - return on investment and time to market rules the industry. In my interpretation the current range of Nortel products developed in Erlang are successfully because the time to market is very short. It takes longer to develop in C - the product is delivered later and you loose market share during the development period. If I was a venture capitalist Id go for early time to market and high quality. Not fast and late. Microsoft originally gained market share by delivering early and buggy - now we can deliver early and with very few bugs. All that is needed to overthrow the current hegemony is a consistent growth rate that is higher than the opposition. > But I grant you that MIPS is not always the best "kind" of speed. > "Speed" of maintenance is probably the critical thing in my mind. > Consider: if you don't put the work into making the language > implementation fast, programmers are going to write their own code in an > optimized manner to compensate - making it much harder to maintain. But but ... at home I have my good 'od work horse a 300 MHz Celeron - is is "fast enough" for everything *except* video rendering. I have *never* rewritten an Erlang program because it was too slow. I have (sometimes) written an Erlang program that was too slow - but in these cases a bit more thought convinced me that no language would help - ie my algorithms were intrinsically slow no matter how I implemented them. > > > 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) > > ...and design a new language :) > > -Chris > From luke@REDACTED Wed Sep 24 11:24:01 2003 From: luke@REDACTED (Luke Gorrie) Date: 24 Sep 2003 11:24:01 +0200 Subject: new syntax - a provocation In-Reply-To: References: Message-ID: Joe Armstrong writes: > On Tue, 23 Sep 2003, Chris Pressey wrote: > > > > << 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 >> > > > > Yes, but can you still ensure constant time operations on atoms? > > There are two ways of doing this: What about: Atoms are unique objects just like from make_ref() but with names. There is a global hashtable for list_to_atom/1 to find (or create) the atom with a particular name. All references to atoms from beam files, binary_to_term, etc, are resolved by list_to_atom/1. References from the atom table to the atom objects are "weak", i.e. are not used to mark atoms as live during garbage collection. When an atom is garbage collected, it is removed from the hash table. If someone later wants an atom with the same name, a new one is created which is then the only existing atom with that name. Then if there are no references to an atom (except from the atom table) it is garbage collected and forgotten. So long as there are N>0 references to a particular atom, they all refer to the same object and can be compared in unit time. (Oops. Did I just assume a unified heap, or separate space for atoms?) -Luke From vlad_dumitrescu@REDACTED Wed Sep 24 12:05:38 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Wed, 24 Sep 2003 12:05:38 +0200 Subject: essential Erlang References: <3F71571C.4040309@manderp.freeserve.co.uk> Message-ID: > Why not start from the outset with the Mach kernel, as are the Gnu-HURD > team, and build a native Core-Erlang system on top of that? I'd first go with making Erlang a virtual OS, seems easier. [That's a relative measure anyway... Just trying to split apart parts of ERTS is a lot of work. I tried without success the naive solution of just removing selected applications from the lib directory :-) ] > Mach provides the process scheduling and message passing primitives. Are they fast enough? I feel L4 matches better... /Vlad From bry@REDACTED Wed Sep 24 12:27:47 2003 From: bry@REDACTED (bryan) Date: Wed, 24 Sep 2003 12:27:47 +0200 Subject: yaws php? In-Reply-To: Message-ID: <002b01c38286$8229c570$2001a8c0@bryans> In the release notes to version 1.30 of Yaws it says that Full...PHP support exists. Can someone point me to some documentation for getting php up and running under Yaws? From enano@REDACTED Wed Sep 24 12:54:57 2003 From: enano@REDACTED (Miguel Barreiro Paz) Date: Wed, 24 Sep 2003 12:54:57 +0200 (CEST) Subject: essential Erlang In-Reply-To: References: <3F71571C.4040309@manderp.freeserve.co.uk> Message-ID: > > Why not start from the outset with the Mach kernel, as are the Gnu-HURD > > team, and build a native Core-Erlang system on top of that? Because development would be abysmally slow, as it is in GNU Hurd (yes, I'm wearing asbestos underwear today) and a couple of developers at most would understand the subtleties of the microkernel internals. > I'd first go with making Erlang a virtual OS, seems easier. In my humble opinion Erlans (well, the ERTS) is already a virtual OS. It offers process management and isolation, access to external resources and devices, memory management, and isolates user code from the cold underlying hardware. It does lack isolation among different identities as multiuser OSs do - but note that these identities don't have to be users. IBM VM calls virtualized machines "users", and gives each of them a virtual hardware image. Wouldn't running erlang inside erlang be beautiful? From erlang@REDACTED Wed Sep 24 13:25:17 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Wed, 24 Sep 2003 12:25:17 +0100 Subject: essential Erlang In-Reply-To: References: <3F71571C.4040309@manderp.freeserve.co.uk> Message-ID: <3F717F1D.5050506@manderp.freeserve.co.uk> (Quickly googles L4 and finds an implementation of Linux running on an L4 microkernel. Cool!) Okay Vlad, Now that I'm a bit better informed, I don't think the underlying microkernel should inhibit anyone from having a stab at it. The kernel primitives ought to be sufficiently equivalent to enable replacing one with the other without much impact. Slow at this stage is not be my primary concern. The practicability question is more interesting to me. After that, faster microkernels may be tried to suit real time applications. Pete. Vlad Dumitrescu wrote: >>Why not start from the outset with the Mach kernel, as are the Gnu-HURD >>team, and build a native Core-Erlang system on top of that? > > > I'd first go with making Erlang a virtual OS, seems easier. > > [That's a relative measure anyway... Just trying to split apart parts of ERTS is > a lot of work. I tried without success the naive solution of just removing > selected applications from the lib directory :-) ] > > >>Mach provides the process scheduling and message passing primitives. > > > Are they fast enough? I feel L4 matches better... > > /Vlad > > > From ulf.wiger@REDACTED Wed Sep 24 13:26:23 2003 From: ulf.wiger@REDACTED (=?iso-8859-1?Q?Ulf_Wiger_=28=C4L2/EAB=29?=) Date: Wed, 24 Sep 2003 13:26:23 +0200 Subject: top poster Message-ID: <76E5F712842F5F49A35738622BAA0F4F9EA740@ESEALNT442.al.sw.ericsson.se> I ran my tool to extract some statistics from the erlang-questions mailing list web archive. Mailing list activity seems to grow on average, now wobbling at around 300 posts/month from some 80-100 different people. The peak so far was in February 2003, with 740 posts from 121 different email addresses. The (truncated) all-time list of top posters currently looks like this, not accounting for the fact that people may use different email addresses from time to time. /Uffe (my 669th post so far ;-) etxuwig@REDACTED 568 vances@REDACTED 271 Sean.Hinde@REDACTED 265 luke@REDACTED 259 cpressey@REDACTED 246 vlad_dumitrescu@REDACTED 196 kent@REDACTED 194 klacke@REDACTED 159 joe@REDACTED 152 richardc@REDACTED 133 spearce@REDACTED 131 eleberg@REDACTED 127 mickael.remond@REDACTED 122 Sean.Hinde@REDACTED 121 bjorn@REDACTED 121 matthias@REDACTED 118 per@REDACTED 102 jamesh@REDACTED 101 Marc.Vanwoerkom@REDACTED 100 rv@REDACTED 99 Vlad.Dumitrescu@REDACTED 97 vladdu@REDACTED 95 cyberlync@REDACTED 92 hakan@REDACTED 91 svg@REDACTED 91 erlang@REDACTED 88 tobbe@REDACTED 79 hal@REDACTED 78 jay@REDACTED 74 enano@REDACTED 72 mbj@REDACTED 72 sam@REDACTED 70 raimo@REDACTED 70 per@REDACTED 69 Chandrashekhar.Mullaparthi@REDACTED 69 fritchie@REDACTED 65 francesco@REDACTED 65 martin@REDACTED 61 bjarne@REDACTED 59 tobbe@REDACTED 58 Chandrashekhar.Mullaparthi@REDACTED 52 mikael.karlsson@REDACTED 52 matthias@REDACTED 50 erlang@REDACTED 49 sureshsaragadam@REDACTED 48 Bruce@REDACTED 48 ulf.wiger@REDACTED 46 jocke@REDACTED 45 lennart.ohman@REDACTED 45 mickael.remond@REDACTED 43 thomasl_erlang@REDACTED 40 raimo.niskanen@REDACTED 40 robert.virding@REDACTED 38 jhague@REDACTED 37 peter@REDACTED 37 thomas@REDACTED 37 garry@REDACTED 36 dgud@REDACTED 36 nick@REDACTED 36 enewhuis@REDACTED 35 daniel.dudley@REDACTED 35 DANIESC.SCHUTTE@REDACTED 33 apeake@REDACTED 32 mikpe@REDACTED 32 ingela@REDACTED 31 ulf.wiger@REDACTED 30 joe@REDACTED 30 rpettit@REDACTED 29 per@REDACTED 28 hp@REDACTED 28 david.wallin@REDACTED 27 crd@REDACTED 26 fredrik.linder@REDACTED 26 bernardp@REDACTED 25 sean.hinde@REDACTED 24 gunilla@REDACTED 24 ltaesch@REDACTED 24 scott@REDACTED 24 tony@REDACTED 23 From vlad_dumitrescu@REDACTED Wed Sep 24 13:30:03 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Wed, 24 Sep 2003 13:30:03 +0200 Subject: essential Erlang References: <3F71571C.4040309@manderp.freeserve.co.uk> Message-ID: From: "Miguel Barreiro Paz" > In my humble opinion Erlans (well, the ERTS) is already a virtual OS. It > offers process management and isolation, access to external resources and > devices, memory management, and isolates user code from the cold > underlying hardware. Yes, it is, but I was referring to the clean separation that I mentioned before. Right now it's a monolithic VOS, possibly even an ancient-style one. > It does lack isolation among different identities as > multiuser OSs do - but note that these identities don't have to be users. > IBM VM calls virtualized machines "users", and gives each of them a > virtual hardware image. In Erlangish, would we call it a node? It's an interesting idea to somehow give nodes different rights, even if it goes somewhat against the transparency property of Erlang distribution. /Vlad From erlang@REDACTED Wed Sep 24 13:35:24 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Wed, 24 Sep 2003 12:35:24 +0100 Subject: essential Erlang In-Reply-To: References: <3F71571C.4040309@manderp.freeserve.co.uk> Message-ID: <3F71817C.8090609@manderp.freeserve.co.uk> Hi Miguel, Miguel Barreiro Paz wrote: > Because development would be abysmally slow, as it is in GNU Hurd (yes, > I'm wearing asbestos underwear today) and a couple of developers at most > would understand the subtleties of the microkernel internals. Well, I did say they _still_ haven't any product yet. So yes, maybe not the best foundation, but as Vlad suggested there is more than enough to choose from. > In my humble opinion Erlans (well, the ERTS) is already a virtual OS. Yes, but "virtual" is the key word. Why not dispense with unnecessary baggage and make it "physical"? Hopefully giving Erlang a replacement for VxWorks... and I think a few people would *really* like that! > Wouldn't running erlang inside erlang be beautiful? Hehe (-: The L4Linux project may be a bridge toward L4Erlang, but who _really_ wants this sooooo badly and can make time to scratch this itch? Pete. From vlad_dumitrescu@REDACTED Wed Sep 24 13:44:22 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Wed, 24 Sep 2003 13:44:22 +0200 Subject: essential Erlang References: <3F71571C.4040309@manderp.freeserve.co.uk> <3F717F1D.5050506@manderp.freeserve.co.uk> Message-ID: From: "Peter-Henry Mander" > Now that I'm a bit better informed, I don't think the underlying > microkernel should inhibit anyone from having a stab at it. No, of course not. The problem seems to be that (as Miguel pointed out) not much seems to happen on this front as of late. It seems to me that it's difficult to know where things are heading. My favourite would have been an exokernel, but the only known to me implementation (at MIT http://www.pdos.lcs.mit.edu/exo.html) seems not to have been updated for many years... > The kernel > primitives ought to be sufficiently equivalent to enable replacing one > with the other without much impact. Ermm, I am not sure about that. From what I've been browsing, there are many variants that appear to be quite different. Anyway, I'd still begin with breaking ERTS down, so that it will be easier to know what precise features one wants from the kernel. /Vlad From ok@REDACTED Wed Sep 24 03:29:09 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Wed, 24 Sep 2003 13:29:09 +1200 (NZST) Subject: new syntax - a provocation Message-ID: <200309240129.h8O1T9wW504926@atlas.otago.ac.nz> Joe Armstrong wrote: - Proper structs << junk the record stuff. thus has been discussed in previous mails >> I never thought I'd recommend anything from IBM Prolog, but it turns out that "IBM PROLOG for 370" had something that LIFE had and that I've long wanted in Erlang. The things I want have been known by various names in various languages: "tables" in SNOBOL, "Dictionaries" in Smalltalk, "associative arrays" in AWK, "hashes" in Perl, "psi-terms" in LIFE, "feature structures" in linguistics, and who knows what elsewhere. In this message, I'm going to call them dictionaries. A dictionary is a finite collection of (key,value) pairs such that all keys are atoms and no two keys are equal. The values may be any Erlang terms. Functions: is_dictionary(Dict) -> Boolean if Dict is a dictionary, the result is 'true', otherwise 'false'. In a guard, succeeds or fails instead of returning true or false. Cost: O(1). dictionary_to_list(Dict) -> [{K1,V1},....,{Kn,Vn}] where the keys are in strictly ascending order Cost: O(n). list_to_dictionary([{K1,V1},...,{Kn,Vn}]) -> Dict The argument must be a well formed list; each of its elements must be a pair; and the first element of each pair must be an atom. The atoms need not be distinct. If two pairs have the same key, the first (leftmost) value is used and the later pair is ignored. Cost: O(n.lgn). dictionary_size(Dict) -> Integer The result is the same as length(dictionary_to_list(Dict)) would have been, but this form should be usable in guards. Cost: O(1). dictionary_has(Dict, Key) -> Boolean The result is the same as lists:keymember(Key, 1, dictionary_to_list(Dict)) would have been. In a guard, this succeeds or fails instead of returning true or false. Cost: O(lg n). dictionary_value(Dict, Key) -> Value | error exit The result is the same as ({value,{_,X}} = lists:keysearch(Dict, 1, Key), X) would have been, except of course for not binding X and for a more informative error report. In a guard expression, this makes the guard fail instead of signalling an error. Cost: O(lg n). dictionary_search(Dict, Key) -> {value,Value} | false The result is the same as case lists:keysearch(Dict, 1, Key) of {value,{_,X}} -> {value,X}; false -> false end, woudl have been, except of course for not binding X and for a more informative error report. As this may create a new tuple, it is not allowed in a guard. Cost: O(lg n). dictionary_sum(Dict1, Dict2) -> Dict The result is the same as list_to_dictionary(lists:keymerge(1, dictionary_to_list(Dict1), dictionary_to_list(Dict2))) would have been, except for more informative error reports. As the code above implies, if a key is present in both dictionaries, the value in Dict1 is used. Cost: O(|Dict1| + |Dict2|) dictionary_keys(Dict) -> [Key] The result is the same as [K || {K,_} <- dictionary_to_list(Dict)] would have been, except for more informative error reports. In particular, the list of keys is sorted. Cost: O(|Dict|). dictionary_without(Dict, Keys) -> Dict' The result is the same as list_to_dictionary( [{K,V} || {K,V} <- dictionary_to_list(Dict), not lists:member(K, Keys)]) would have been, except for more informative error reports. In particular, the list of keys is sorted. Cost: O(|Dict| + k.lg k) where k = length(Keys). Equality and ordering: We'd like these to be compatible with set inclusion. A dictionary is not equal to anything that isn't a dictionary. Two dictionaries D1, D2 are equal if and only if dictionary_to_list(D1) is equal to dictionary_to_list(D2). For ordering, dictionaries go after tuples. To order two dictionaries, 1. First order them by size. 2. If they have the same size, they have the same relative order that dictionary_to_list(D1), dictionary_to_list(D2) would have. Under these rules, dictionary_without(D, Keys) <= D, with equality if and only if Keys == []. Special syntax: '<{' [maplet {',' maplet}*] ['|' expression] '}>' is an expression, where maplet ::= expression '->' expression <{ K1->V1,...,Kn->Vn | D }> is equivalent to list_to_dictionary([{K1,V1},...,{Kn,Vn}|dictionary_to_list(D)]) except, as usual, for error messages, and for a compile-time opportunity. If the keys K1...Kn are atoms at compile time and there is no |D part, the cost is O(n), plus of course the cost of evaluating the V1...Vn. Comprehension: There isn't any need for a special dictionary comprehension form, because list_to_dictionary([{K,V} || ... ]) can be recognised by a compiler. While I would _like_ to recommend a special form for iterating over the keys and values of a dictionary in a list comprehension, once again K <- dictionary_keys(D) and {K,V} <- dictionary_to_list(D) can be recognised by a compiler, so no special form is needed. Pattern matching: '<{' {pmaplet {',' pmaplist}*] ['|' variable] '}>' is a pattern, where pmaplet ::= atom '->' pattern and all the atoms appearing as keys in a dictionary pattern must be different. If there is a |variable part, the variable may not appear elsewhere in the same pattern or the pattern's related guard. (This condition is easily met if the variable is an anonymous one.) <{ k1->P1, ..., kn->Pn }> = Dict is equivalent to D = Dict, is_dictionary(D), dictionary_size(D) == n, % note == P1 = dictionary_value(D, k1), ..., Pn = dictionary_value(D, kn) where D is a new variable. <{ k1->P1, ..., kn->Pn | Var }> = Dict is equivalent to D = Dict, is_dictionary(D), dictionary_size(D) >= n, % note >= P1 = dictionary_value(D, k1), ..., Pn = dictionary_value(D, kn), Var = dictionary_without(D, [k1,...,kn]) where D is a new variable. If the variable is an anonymous variable, the call to dictionary_without/2 is omitted. If the variable is not an anonymous variable, the call to dicitonary_without/2 (which is by now known to be safe) is postponed till _after_ the guard. The cost of matching a dictionary pattern with n variables against a dictionary value with m keys is O(n+m) plus the cost of matching the element patterns. In fact we can do better: O(min(n+m, n.lg m)). We expect that <{timeout->T|_}> = D will take O(lg |D|) time, the same as T = dictionary_value(D, timeout) (and in fact a little faster, because the ocmpiler must verify that timeout is an atom, while dictionary_value/2 would check at run time). An obvious question is "why not use the 'dict' module?" Answers: (1) When we know that something is a dictionary, we can use a more space-efficient representation. For example, instead of [{K1,V1},...,{Kn,Vn}] -- (n list cells + n 2-tuples) we can use {dict,K1,V1,...,Kn,Vn} -- one 2n+1-tuple (not really a tuple) which is likely to take somewhat less than half the space. (2) When we know that something is a dictionary, we can use a more time-efficient representation. For example, if the keys K1...Kn as shown above are in standard order, lookups can be done in O(lg n) time instead of O(n) time. (3) When the representation is not visible to the programmer, the run-time system may use several different representations. For example, here are some obvious ones: linear array as shown above, some kind of binary search tree (so that unchanged chunks can be shared), some kind of hash table (so that lookup can be O(1)). (4) There are lots of "functional array"/"persistent array" implementations in the literature which could be used to make setelement/3 take O(1) time; these could be adapted to make updates to dictionaries fast too, provided the representation is not exposed. (5) With the 'dict' module you get a somewhat less than obvious textual representation, which could mean other things. With a built in data type you can get "just right" textual representation. (6) With 'dict' you don't get to do dictionary stuff in patterns or guards. All of this could be said of other data structures, but this particular one is of proven utility in many programming languages and of fairly wide occurrence (as "list of options") in Erlang itself. It could replace many uses of records, e.g., <{ mode->M, uid->U, gid->G | _}> = posix:stat(FileName), and it can be used to provide keyword parameters for functions. - 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.>> Hmm. I had always assumed that "message sending is unreliable, in that messages might not arrive" meant that if a process's mailbox was filling up too fast, new messages could simply be discarded. Is that not so? 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 would be very interested in seeing any design notes Joe might have, even scrawls on paper napkins. Increase the isolation property of processes. This has to be right. My very first experience of threads in a high level language was also my introduction to Xerox Lisp Machines (back in 1984): - I brought up a file browser. I saw something that looked interesting, but didn't want to lose my context, so - I brought up another file browser. The system locked up almost at once. - The next N minutes were spent rebooting the system... Big lesson: you *can't* rely on the programmer to remember all the locking; you either need language support for automatically locking the right things or a language where you don't need any locks in the first place. From erlang@REDACTED Wed Sep 24 10:34:36 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Wed, 24 Sep 2003 09:34:36 +0100 Subject: essential Erlang In-Reply-To: References: Message-ID: <3F71571C.4040309@manderp.freeserve.co.uk> Hi Vlad, It sounds suspiciously like a microkernel architecture that was in vogue in the '80s. I think the Gnu-HURD is still trying to push the concept to its logical limits, but there's no production-quality OS from them yet. Windows-NT was initially an object oriented microkernel, but pragmatism and marketing soon corrupted the initially clean concept. Linux, being a pragmatic venture from the outset never pretended to be a microkernel, and perpetuates the monolithic kernel concept, with claims that this is the only way to achieve high performance without compromise. But Erlang _proves_ (at least to me) that lightweight processes and massively concurrent systems can equal or surpass monolithic systems in practice. With the advantage of being easier to use and to implement complex systems than with any other language I know of. Why not start from the outset with the Mach kernel, as are the Gnu-HURD team, and build a native Core-Erlang system on top of that? Mach provides the process scheduling and message passing primitives. Erlang can be used to implement the higher-level services. This project may even ride upon Gnu-HURD to give it a starting block, and give support to the Gnu-HURD. I think this could be lots of fun! (-: Pete. Vlad Dumitrescu wrote: [...] > After describing this architecture, it begins to look like a OS kernel (I think) > and I am pleased to notice that :-) In the future maybe this will be *the* OS... [..] > regards, > Vlad From Bengt.Kleberg@REDACTED Wed Sep 24 14:38:31 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Wed, 24 Sep 2003 14:38:31 +0200 Subject: essential Erlang In-Reply-To: <3F71571C.4040309@manderp.freeserve.co.uk> References: <3F71571C.4040309@manderp.freeserve.co.uk> Message-ID: <3F719047.5070709@ericsson.com> Peter-Henry Mander wrote: ...deleted > Why not start from the outset with the Mach kernel, as are the Gnu-HURD > team, and build a native Core-Erlang system on top of that? Mach reading the mailing lists (ex: http://lists.debian.org/debian-hurd/2003/debian-hurd-200308/msg00114.html) i think that gnu-hurd on gnu-mach is a prototype. some amelioration would be found by moving to oskit-mach, but the major developers have decided that production status can ''only'' be achived on l4. and that in a 3-5 years time frame. bengt From joachim.durchholz@REDACTED Wed Sep 24 16:06:52 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Wed, 24 Sep 2003 16:06:52 +0200 Subject: essential Erlang In-Reply-To: References: Message-ID: <3F71A4FC.9080806@web.de> Vlad Dumitrescu wrote: > After describing this architecture, it begins to look like a OS kernel (I think) > and I am pleased to notice that :-) In the future maybe this will be *the* OS... > > [...] > > Is this only an utopia, or could there be something that will work in real life? Yes, it is an utopia. An OS is much more than processes. It needs device drivers, and unless you want to port all application software, it also needs a Posix layer (and probably Linux and/or Windows compatibility, since Posix isn't enough to run most application software). All of the above are moving targets, which means it is a *huge* amount of software to be written, tested, and (worst of all) maintained. Well, you said "OS kernel", not "OS". So the question becomes: would Erlang-as-an-OS-kernel be attractive for OS developers? I wouldn't hold my breath for that: most existing OSes already have kernels and don't want to plug another one into their software ("never touch a running system" after all). Any OSes that would use Erlang as a kernel will have to be written in the future. And doing design decisions for the off chance that Erlang will look useful the next-generation open-source OS makers? I doubt that this would be helpful... after all, Erlang is an application programming language, not a systems programming language. I'd find it more interesting if there were a way of making Erlang interface better with C programs. I've been interfacing Windows with a non-C language, and it's been a pain even though it was a direct-call interface - I'm wondering how much worse it will be to write a driver program for Erlang... (semiautomatically generating drivers from C include files would help a lot) Regards, Jo From joe@REDACTED Wed Sep 24 17:19:44 2003 From: joe@REDACTED (Joe Armstrong) Date: Wed, 24 Sep 2003 17:19:44 +0200 (CEST) Subject: new syntax - a provocation In-Reply-To: <200309240129.h8O1T9wW504926@atlas.otago.ac.nz> Message-ID: On Wed, 24 Sep 2003, Richard A. O'Keefe wrote: > Joe Armstrong wrote: > - Proper structs > > << junk the record stuff. thus has been discussed in previous > mails >> > > I never thought I'd recommend anything from IBM Prolog, but it turns out > that "IBM PROLOG for 370" had something that LIFE had and that I've long > wanted in Erlang. The things I want have been known by various names in > various languages: "tables" in SNOBOL, "Dictionaries" in Smalltalk, > "associative arrays" in AWK, "hashes" in Perl, "psi-terms" in LIFE, > "feature structures" in linguistics, and who knows what elsewhere. > > > In this message, I'm going to call them dictionaries. > > A dictionary is a finite collection of (key,value) pairs such that > all keys are atoms and no two keys are equal. The values may be any > Erlang terms. > > Functions: ... cut ... These are what I called "proper structs" I posted an article about this in 2001 I can repost if you're interested ... My structs were written ~{K1=V1, K2=V2, ...} or ~Tag{K1=V1, ...} (So that you could name an entire struct) Update was written Var~{K1=NewV1, ...} etc. ~Tag{...} works just like #Tag{....} works today but with the difference that everything is dynamic - so whereas #Tag{...} needs a -record(Tag, {...}) definition ~Tag{...} does not /Joe From joachim.durchholz@REDACTED Wed Sep 24 17:29:45 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Wed, 24 Sep 2003 17:29:45 +0200 Subject: Dictionaries In-Reply-To: <200309240129.h8O1T9wW504926@atlas.otago.ac.nz> References: <200309240129.h8O1T9wW504926@atlas.otago.ac.nz> Message-ID: <3F71B869.6090101@web.de> Richard A. O'Keefe wrote: > In this message, I'm going to call them dictionaries. > > A dictionary is a finite collection of (key,value) pairs such that > all keys are atoms and no two keys are equal. The values may be any > Erlang terms. Sounds good :-) I'd prefer to have keys that are more than atoms. Full Erlang terms would be most flexible, but in practice, you need a data structure that has a comparison operation - with that, you can use binary trees (hopefully with improvements that prevent degenerate cases). Even better would be keys where the key value gives you an indication of how far into the general sort sequence it is (e.g. when looking up a telephone directory, if you know the name starts with "P", you don't do a bisection search, you start at roughly 60% - translated to searching algorithms, this makes B-Trees and their ilk feasible and useful). In practice, I'd want the following types of key: * Atoms (if the key space is limited) * Strings (if the key space is unlimited - think DoS attacks...) * Numbers (I have geographical data, I *need* this *g*) (unlimited-size integers would be fine though) > Equality and ordering: > > We'd like these to be compatible with set inclusion. Mixing set semantics with dictionaries is almost sure to give serious trouble. The problem is that, depending on the situation, programmers will want to set dictionaries as different sets: 1) As the set of its keys. 2) As the set of its values. 3) As the set of its key-value pairs. > An obvious question is "why not use the 'dict' module?" > > Answers: > (1) When we know that something is a dictionary, we can use a more > space-efficient representation. For example, instead of > [{K1,V1},...,{Kn,Vn}] -- (n list cells + n 2-tuples) > we can use > {dict,K1,V1,...,Kn,Vn} -- one 2n+1-tuple (not really a tuple) > which is likely to take somewhat less than half the space. Such a space-efficient representation will be useful iff it is known that the dictionary will not change. Hmm... yes, the proposal has no way of adding key-value pairs. Which leads me to the question how to create a dictionary with an additional key-value pair? Such creation should not have an amortized worse than O(number-of-key-value-pairs * log |Dictionary|) efficiency to be useful. > (2) When we know that something is a dictionary, we can use a more > time-efficient representation. For example, if the keys K1...Kn > as shown above are in standard order, lookups can be done in > O(lg n) time instead of O(n) time. Then the dict implementation could be improved. Simple tree-balancing algorithms that always maintain an amortized O(log |Dictionary|) update and retrieval time exist, even without destructive updates; see Chris Okasaki's "Purely Functional Data Structures". Regards, Jo From cpressey@REDACTED Wed Sep 24 18:47:05 2003 From: cpressey@REDACTED (Chris Pressey) Date: Wed, 24 Sep 2003 09:47:05 -0700 Subject: dictionaries (was Re: new syntax - a provocation) In-Reply-To: <200309240129.h8O1T9wW504926@atlas.otago.ac.nz> References: <200309240129.h8O1T9wW504926@atlas.otago.ac.nz> Message-ID: <20030924094705.5c7d2433.cpressey@catseye.mine.nu> On Wed, 24 Sep 2003 13:29:09 +1200 (NZST) "Richard A. O'Keefe" wrote: > Joe Armstrong wrote: > - Proper structs > > << junk the record stuff. thus has been discussed in previous > mails >> > > I never thought I'd recommend anything from IBM Prolog, but it turns > out that "IBM PROLOG for 370" had something that LIFE had and that > I've long wanted in Erlang. The things I want have been known by > various names in various languages: "tables" in SNOBOL, > "Dictionaries" in Smalltalk,"associative arrays" in AWK, "hashes" in > Perl, "psi-terms" in LIFE,"feature structures" in linguistics, and who > knows what elsewhere. Every data structures textbook I've seen calls them "dictionaries" too, and Erlang calls them "dicts", so I very much agree with your choice of terminology. > > In this message, I'm going to call them dictionaries. > > A dictionary is a finite collection of (key,value) pairs such that > all keys are atoms and no two keys are equal. The values may be any > Erlang terms. > > Functions: > [... API almost identical to the dict module's ...] > [...] > Special syntax: > > '<{' [maplet {',' maplet}*] ['|' expression] '}>' > > is an expression, where > maplet ::= expression '->' expression > > <{ K1->V1,...,Kn->Vn | D }> I think I like this better than Joe's syntax, but I'm not sure. Either way it's a sure sign that the available syntactic markers are getting a bit scant :) > An obvious question is "why not use the 'dict' module?" Indeed. > Answers: > (1) When we know that something is a dictionary, we can use a more > space-efficient representation. For example, instead of > [{K1,V1},...,{Kn,Vn}] -- (n list cells + n 2-tuples) > we can use > {dict,K1,V1,...,Kn,Vn} -- one 2n+1-tuple (not really a tuple) > which is likely to take somewhat less than half the space. > > (2) When we know that something is a dictionary, we can use a more > time-efficient representation. For example, if the keys K1...Kn > as shown above are in standard order, lookups can be done in > O(lg n) time instead of O(n) time. > > (3) When the representation is not visible to the programmer, the > run-time > system may use several different representations. For example, > here are some obvious ones: linear array as shown above, some > kind of binary search tree (so that unchanged chunks can be > shared), some kind of hash table (so that lookup can be O(1)). > > (4) There are lots of "functional array"/"persistent array" > implementations > in the literature which could be used to make setelement/3 take > O(1) time; these could be adapted to make updates to dictionaries > fast too, provided the representation is not exposed. > > (5) With the 'dict' module you get a somewhat less than obvious > textual > representation, which could mean other things. With a built in > data type you can get "just right" textual representation. I don't follow _any_ of these arguments. It's my understanding that the representation of dicts is _undefined_. (You didn't go peeking and write code like 'case A of {dict,_,_,...} -> ...', did you? :) Because the representation of dicts is undefined, they could change anytime in the future, perhaps drastically (e.g. becoming BIFs.) > (6) With 'dict' you don't get to do dictionary stuff in patterns or > guards. All that's needed for that is a special _notation_ for dictionaries (which, to be clear, is _not_ the same thing as a _representation_ in this sense.) I've said it before, but I think the path to take here, to maximize the benefit for code that's already been written, is: - implement dictionaries directly in BEAM (any number of available C implementations would probably do the trick sufficiently - in fact we already have a very efficient associative storage mechanism that might work just fine. what's it called again? oh yah. 'ETS' :) - map the dict module to BIFs (we don't need a new API for this - and existing code that uses dicts gets performance/extensibility benefits) - add a syntax for pattern-matching dictionaries (the only real advance) > All of this could be said of other data structures, but this > particular one is of proven utility in many programming languages and > of fairly wide occurrence (as "list of options") in Erlang itself. It > could replace many uses of records, e.g., > > <{ mode->M, uid->U, gid->G | _}> = posix:stat(FileName), > > and it can be used to provide keyword parameters for functions. Completely 100% agreed (and by Joe too I think, but he calls them 'structs' instead.) On Wed, 24 Sep 2003 17:29:45 +0200 Joachim Durchholz wrote: > Richard A. O'Keefe wrote: > > In this message, I'm going to call them dictionaries. > > > > A dictionary is a finite collection of (key,value) pairs such that > > all keys are atoms and no two keys are equal. The values may be any > > Erlang terms. > > Sounds good :-) > > I'd prefer to have keys that are more than atoms. Ditto. No sense taking a step backwards. > Full Erlang terms > would be most flexible, but in practice, you need a data structure > that has a comparison operation Why? Dictionaries aren't ordered. > In practice, I'd want the following types of key: > * Atoms (if the key space is limited) > * Strings (if the key space is unlimited - think DoS attacks...) > * Numbers (I have geographical data, I *need* this *g*) > (unlimited-size integers would be fine though) In practice, I'd want the same types of keys that are available these days - arbitrary Erlang terms. 1> D=dict:new(). {dict,0, ... } 2> D1=dict:store({key, ["%#", 42, 7.01, self()]}, value, D). {dict,1, ... } 3> dict:find({key,["%#",42,7.01000,list_to_pid("<0.27.0>")]}, D1). {ok,value} -Chris From erlang@REDACTED Wed Sep 24 13:47:27 2003 From: erlang@REDACTED (Inswitch Solutions - Erlang Evaluation) Date: Wed, 24 Sep 2003 13:47:27 +0200 Subject: How to detect node down Message-ID: <00fe01c38292$b8895570$1e00a8c0@design> I have two nodes in different machines (Windows 2000) and I'm using the dist_auto_connect default kernel value. Does anyone know how can I detect a "node down" in each node when disconnecting the network cable ? Is there a system message for this? Thanks again, Eduardo Figoli INSwitch Solutions -------------- next part -------------- An HTML attachment was scrubbed... URL: From cpressey@REDACTED Wed Sep 24 19:16:11 2003 From: cpressey@REDACTED (Chris Pressey) Date: Wed, 24 Sep 2003 10:16:11 -0700 Subject: new syntax - a provocation In-Reply-To: References: <20030923091753.21901e6e.cpressey@catseye.mine.nu> Message-ID: <20030924101611.4771f1de.cpressey@catseye.mine.nu> On Wed, 24 Sep 2003 10:56:33 +0200 (CEST) Joe Armstrong wrote: > On Tue, 23 Sep 2003, Chris Pressey wrote: > > > > << 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 >> > > > > Yes, but can you still ensure constant time operations on atoms? > > There are two ways of doing this: I see. That's good news. > > Erlang already has some of the best isolation properties of any > > language, though... the only way I can think to improve them (beyond > > what I've already mentioned) is to make locking easier. But locking > > is already easy! So do you have any other concrete ideas on what > > would need to be added/removed/fixed to make processes even better > > isolated? > > > > Interesting - I'd *much* prefer a solution based on implicit contracts > and no locking - locking distributed objects makes me shudder in > horror .. Let me clarify - I don't mean "client asks server for a lock, and server gives client a locking ticket which it hopes the client will return." I mean "client asks server for a resource and the server locks it *internally* for the duration of the transaction." I fully admit the former is Way Bad Design. Perhaps the word "serialization" would have been a better choice than "locking." > At the outer level of abstraction processes are black boxes. Their > communication is regulated by contracts. Contracts can specify > functional behaviour (types) and non-functional behaviour > (example, I will reply within 10ms, I will send max 100 > messages/hour). I see the value in establishing contracts, however, it is a bit like strong typing: it can only really be done at design/compile time. (There's no way to check contracts at runtime, AFAICS: you just have to be trusting.) And we've all seen the threads about how Erlang programmers would rather use an ad-hoc approach that doesn't slow them down (hmmm) than spend all their time getting the design prim and proper before writing a single line of code. Although I would love to have a contract checking system available - I'd rather just start off writing untrusting code. > This is why I'd like to tightly integrate the UBF stuff into Erlang, > and provide wrappers so that components can be written in any > language. > > > > The "make it slower" track has been ignored. > > > > For better or worse, speed does rule the industry. > > I disagree - return on investment and time to market rules the > industry. That's a very good point. Hmm... I do think it's related. If your customers use your product to get _their_ product to market (or otherwise achieve some sort of goal) quickly, then, your product has to be fast :) It could all go under a general umbrella of 'expedience'... But it is of course not that simple. You're right - it's more psychological than industrial. Speed is *sexy*. No one is concerned with making the source code to Yaws less efficient just so it can be more easily understood. (Well, you and I are, kind of (looking at pico & OpenFlax :) but I think we're in the minority...) > But but ... at home I have my good 'od work horse a 300 MHz Celeron - > is is "fast enough" for everything *except* video rendering. > > I have *never* rewritten an Erlang program because it was too slow. I personally agree 100%. I'd much rather have something reliable and even more importantly *maintainable* (return on investment extends into the future further than most people would like to think about - look at all the COBOL code that's still out there...) -Chris From vlad_dumitrescu@REDACTED Wed Sep 24 20:41:09 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Wed, 24 Sep 2003 20:41:09 +0200 Subject: essential Erlang References: <3F71A4FC.9080806@web.de> Message-ID: From: "Joachim Durchholz" ... lots of good points about OSs ... > Vlad Dumitrescu wrote: > > After describing this architecture, it begins to look like a OS kernel (I think) > > and I am pleased to notice that :-) In the future maybe this will be *the* OS... > > [...] > > Is this only an utopia, or could there be something that will work in real life? > > Yes, it is an utopia. >From your reply I think you misunderstood me. I'll have to be more careful, it's been a while since using that much English :-) My question referred not to the Erlang OS, but to breaking apart ERTS and OTP into several loosely coupled components. Joe did make a case for it, and I tried to propose a concrete splitting line. Then I began fantasizing :-) > I'd find it more interesting if there were a way of making Erlang > interface better with C programs. I've been interfacing Windows with a > non-C language, and it's been a pain even though it was a direct-call > interface - I'm wondering how much worse it will be to write a driver > program for Erlang... (semiautomatically generating drivers from C > include files would help a lot) That's a problem for me too. I hear EDTK is a good tool, but it doesn't work on Windows. [Side note: Yaws doesn't work either, and I think there are other applications too. Is it a fundamental problem, or just there wasn't anyone who had time and interest?] regards, Vlad From rpettit@REDACTED Wed Sep 24 23:07:15 2003 From: rpettit@REDACTED (Rick Pettit) Date: Wed, 24 Sep 2003 14:07:15 -0700 Subject: How to detect node down In-Reply-To: <00fe01c38292$b8895570$1e00a8c0@design> References: <00fe01c38292$b8895570$1e00a8c0@design> Message-ID: <20030924210715.GB8740@vailsys.com> On Wed, Sep 24, 2003 at 01:47:27PM +0200, Inswitch Solutions - Erlang Evaluation wrote: > > I have two nodes in different machines (Windows 2000) and > I'm using the dist_auto_connect default kernel value. > > Does anyone know how can I detect a "node down" in each node when disconnecting the network cable ? Is there a system message for this? Does this help?: http://www.erlang.org/doc/r9c/doc/index.html and search for monitor_node/2. BTW, I found this by going to www.erlang.org, clicking the documentation link, the clicking on the complete OTP R9C docs, and entering monitor in the index search, then searching for the word monitor in the resultant page. Hope that helps. -Rick P.S. You probably won't detect the node down until the low-level tick-tock heartbeat mechanism fails, which might not be for some time (IIRC the default is 60 seconds). From carsten@REDACTED Wed Sep 24 22:05:08 2003 From: carsten@REDACTED (Carsten Schultz) Date: Wed, 24 Sep 2003 22:05:08 +0200 Subject: yaws php? In-Reply-To: <002b01c38286$8229c570$2001a8c0@bryans> References: <002b01c38286$8229c570$2001a8c0@bryans> Message-ID: <20030924200508.GA15983@penne.localnet> Hi Bryan, it would have been easier to spot your question, had you started a new thread instead of replying. > In the release notes to version 1.30 of Yaws it says that Full...PHP > support exists. Can someone point me to some documentation for getting > php up and running under Yaws? There's a small paragraph buried in the CGI section of the TeX documentation: If you have a Php executable compiled for using CGI in the \verb+PATH+ of the Yaws server, you can enable Php support by adding \verb+php+ to \verb+allowed_scripts+. Requests for pages ending in \verb+.php+ will then result in Yaws executing \verb+php+ and passing the name of the corresponding file to it via the appropriate environment variable. Does that help? Please tell me if you get the PHP stuff working and if it is useful for you. Greetings, Carsten -- Carsten Schultz (2:40, 33:47), FB Mathematik, FU Berlin http://carsten.fu-mathe-team.de/ PGP/GPG key on the pgp.net key servers, fingerprint on my home page. -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 240 bytes Desc: not available URL: From vances@REDACTED Wed Sep 24 22:19:49 2003 From: vances@REDACTED (Vance Shipley) Date: Wed, 24 Sep 2003 16:19:49 -0400 Subject: How to detect node down In-Reply-To: <00fe01c38292$b8895570$1e00a8c0@design> References: <00fe01c38292$b8895570$1e00a8c0@design> Message-ID: <20030924201949.GE51881@frogman.motivity.ca> You can change the tick time with net_adm:set_net_ticktime/2 to have the node recognized as down sooner. -Vance On Wed, Sep 24, 2003 at 01:47:27PM +0200, Eduardo Figoli wtote: } } Does anyone know how can I detect a "node down" in each node when disconnecting the network cable ? Is there a system message for this? From crav@REDACTED Wed Sep 24 19:10:51 2003 From: crav@REDACTED (=?iso-8859-1?Q?Carlos_Rodr=EDguez_Alcal=E1_Villagra?=) Date: Wed, 24 Sep 2003 18:10:51 +0100 Subject: auditToken megaco Message-ID: <005001c382be$cf83e2f0$6600a8c0@carlos> Hi to make this command : MEGACO/1 [172.16.0.1]:2944 Transaction = 1 { Context = - { AuditCapabilities = ui { Audit{Events} }}} |-----------------------------------------------------------------------------| I wrote this code: ****************************** auditcapabilities(ConnHandle, Events)-> AUD=#'AuditDescriptor'{auditToken=Audit}, TermId=ui, AUR=#'AuditRequest'{terminationID = TermId, auditDescriptor = AUD}, CR = #'CommandRequest'{command = {auditCapabilities, AUR}}, AR = #'ActionRequest'{contextId = ?megaco_null_context_id, commandRequests = [CR]}, io:format("AR:~p~n", [AR]), {ProtocolVersion, UserReply}=megaco:call(ConnHandle, [AR], []) **************************** but, auditToken should also be a structure to be able to load Event, rigth? Because, in the RFC3015 page 89 is written: AuditDescriptor ::= SEQUENCE { auditToken BIT STRING { muxToken(0), modemToken(1), mediaToken(2), eventsToken(3), signalsToken(4), digitMapToken(5), statsToken(6), observedEventsToken(7), packagesToken(8), eventBufferToken(9) } OPTIONAL, ... } thanks for your time -------------- next part -------------- An HTML attachment was scrubbed... URL: From erlang@REDACTED Thu Sep 25 08:32:58 2003 From: erlang@REDACTED (Peter-Henry Mander) Date: Thu, 25 Sep 2003 07:32:58 +0100 Subject: auditToken megaco In-Reply-To: <005001c382be$cf83e2f0$6600a8c0@carlos> References: <005001c382be$cf83e2f0$6600a8c0@carlos> Message-ID: <3F728C1A.2080502@manderp.freeserve.co.uk> Hi Carlos, May I suggest reading _both_ the ASN.1 and ABNF grammars, having two descriptions helped me a lot when I was struggling to build the proper data structures. The ASN.1 AuditDescriptor grammar tells me that it is a sequence of tokens, nothing more. I think you may need to look at auditReply where the events are returned as:- auditReturnParameter = (mediaDescriptor / modemDescriptor / muxDescriptor / eventsDescriptor / signalsDescriptor / digitMapDescriptor / observedEventsDescriptor / eventBufferDescriptor / statisticsDescriptor / packagesDescriptor / errorDescriptor / auditItem) The descriptors will contain the information returned from an audit request. /aside Also note that in the extract below there's a _comment_ that auditItem set of tokens may appear in two different constructs, but are not used the same way. The ABNF *should* have specified auditItem as it is, and *additionally* specified auditCapabilitiesItem which excludes DigitMapToken and PackagesToken, to be used in the AuditCapabilities command only. So _you_must_read_the_comments_ in case there's a special case not written in ABNF or ASN.1 (This has been a bugbear for me. No wonder interops are so fraught!) ;;;;;;;;;;;;;;;;;;;; extract of ABNF commandRequest = ( ammRequest / subtractRequest / auditRequest / notifyRequest / serviceChangeRequest) auditRequest = (AuditValueToken / AuditCapToken ) EQUAL TerminationID LBRKT auditDescriptor RBRKT AuditValueToken = ("AuditValue" / "AV") AuditCapToken = ("AuditCapability" / "AC") ;;;;;;;;;;;;;;;;;;;; this indicates that an auditDescriptor ;;;;;;;;;;;;;;;;;;;; is a comma list in text format auditDescriptor = AuditToken LBRKT [ auditItem *(COMMA auditItem) ] RBRKT AuditToken = ("Audit" / "AT") ;at-most-once, and DigitMapToken and PackagesToken are not allowed ;in AuditCapabilities command auditItem = ( MuxToken / ModemToken / MediaToken / SignalsToken / EventBufferToken / DigitMapToken / StatsToken / EventsToken / ObservedEventsToken / PackagesToken ) MuxToken = ("Mux" / "MX") ModemToken = ("Modem" / "MD") MediaToken = ("Media" / "M") SignalsToken = ("Signals" / "SG") EventBufferToken = ("EventBuffer" / "EB") DigitMapToken = ("DigitMap" / "DM") StatsToken = ("Statistics" / "SA") EventsToken = ("Events" / "E") ObservedEventsToken = ("ObservedEvents" / "OE") PackagesToken = ("Packages" / "PG") Carlos Rodr?guez Alcal? Villagra wrote: > > *Hi to make this command :* > MEGACO/1 [172.16.0.1]:2944 > Transaction = 1 { > Context = - { > AuditCapabilities = ui { > Audit{Events} > }}} > |-----------------------------------------------------------------------------| > > > > *I wrote this code:* > ****************************** > > auditcapabilities(ConnHandle, Events)-> > AUD=#'AuditDescriptor'{auditToken=Audit}, > TermId=ui, > AUR=#'AuditRequest'{terminationID = TermId, auditDescriptor = AUD}, > CR = #'CommandRequest'{command = {auditCapabilities, AUR}}, > AR = #'ActionRequest'{contextId = ?megaco_null_context_id, > commandRequests = [CR]}, > io:format("AR:~p~n", [AR]), > {ProtocolVersion, UserReply}=megaco:call(ConnHandle, [AR], []) > > **************************** > > *but, auditToken should also be a structure to be able to load Event, > rigth?* > > * Because, in the RFC3015 page 89 is written: * > > AuditDescriptor ::= SEQUENCE > { > auditToken BIT STRING > { > muxToken(0), modemToken(1), mediaToken(2), > eventsToken(3), signalsToken(4), > digitMapToken(5), statsToken(6), > observedEventsToken(7), > packagesToken(8), eventBufferToken(9) > } OPTIONAL, > ... > } > > *thanks for your time* > From ok@REDACTED Thu Sep 25 08:38:43 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Thu, 25 Sep 2003 18:38:43 +1200 (NZST) Subject: new syntax - a provocation Message-ID: <200309250638.h8P6chgT046325@atlas.otago.ac.nz> Joe Armstrong discussed two ways of implementing atoms without a (permanent) atom table. I don't understand what Mod and Index are. The question is "what do we want a global atom table _for_?" Mainly, so that atom equal/not-equal testing can be O(1). Now, suppose an atom is a tagged pointer to a [hash,size,data] block. You only compare the data if the hash and size are the same. Most Erlang atoms are fairly short, so while this would be slower than whatever it is now, it wouldn't get _that_ much slower. The hash value would be used for indexing in clause/case selection. Or suppose that each module has a fixed set of atoms, known at compile time, plus each process has an atom table. Atoms which the process creates dynamically can be looked up in the process atom table. Atoms that are sent to another process get looked up in the other process's atom table when they arrive. (The aim here is not to ensure uniqueness, but to keep the amount of space used for atom names bounded.) I'm sure that there are lots of implementation alternatives to explore. From rvg@REDACTED Thu Sep 25 10:36:17 2003 From: rvg@REDACTED (Rudolph van Graan) Date: Thu, 25 Sep 2003 10:36:17 +0200 Subject: Xemacs ../ebin and ../include Message-ID: <1F42BB97D787C048BCC519FF28048AC304F055@galileo.ifoni.com> Hi there, I've been trying for the last hour to convince emacs to tell erl to output beam files to ../ebin and to use .hrl files in ../include. However... I cannot find any reference on google to anyone having asked about this, nor can I convince the erlang.org search engine to find anything in the archives... Well, what is the *easy* way of configuring emacs to do this by default? I am sure that there must be lots of you running xemacs that have this configuration? Any help would be greatly appreciated! Thanks again, Rudolph From joe@REDACTED Thu Sep 25 11:12:44 2003 From: joe@REDACTED (Joe Armstrong) Date: Thu, 25 Sep 2003 11:12:44 +0200 (CEST) Subject: new syntax - a provocation In-Reply-To: <200309250638.h8P6chgT046325@atlas.otago.ac.nz> Message-ID: On Thu, 25 Sep 2003, Richard A. O'Keefe wrote: > Joe Armstrong discussed two ways of implementing > atoms without a (permanent) atom table. > > I don't understand what Mod and Index are. Mod is a "Module number" ie a small integer 1..ModMax which indexes a table of know module names. ModMax would not have to be that large. Index is an index into the atom table for an individual module, again a small integer. > > The question is "what do we want a global atom table _for_?" > > Mainly, so that atom equal/not-equal testing can be O(1). > Now, suppose an atom is a tagged pointer to a > [hash,size,data] > block. You only compare the data if the hash and size are the same. > Most Erlang atoms are fairly short, so while this would be slower than > whatever it is now, it wouldn't get _that_ much slower. Yes - my proposals were to speed up this time - it may be that comparing atoms in different modules is done so infrequently and is sufficiently fast that optimisations are not necessary. Comparing atoms in the same module is atomic (since they are just indices not pointers) > The hash value would be used for indexing in clause/case selection. > > Or suppose that each module has a fixed set of atoms, known at > compile time, plus each process has an atom table. Atoms which the > process creates dynamically can be looked up in the process atom table. > Atoms that are sent to another process get looked up in the other > process's atom table when they arrive. Yes. > (The aim here is not to ensure > uniqueness, but to keep the amount of space used for atom names bounded.) > > I'm sure that there are lots of implementation alternatives to explore. Yes - I spent about 10 years thinking about "how to garb the atom table" just to realise that I'd been thinking about the wrong problem. The problem statement should have been "How to design a system that does not need an atom table". Garbing atom tables is *difficult* - a redesign that does not need an atom table is much easier - I came up with two or three schemes for this after a couple of days thought. All of these schemes are slightly slower than the global atom table approach - but I don't think they will be *lot* slower. IMHO the benefits would outweigh the costs. For example, for dynamic XML manipulations I dare not represent an XML parse tree as. {AtomTag, [Attr], [Child]} But have to use the horrible form {String, [Attr], [Child]} For fear that one day the atom table will explode :-) The Atom representation is much better and faster - so the additional time taken using non-atom-table methods might be regained by allowing more natural algorithms to express things like XML parse trees. /Joe From vlad_dumitrescu@REDACTED Thu Sep 25 11:18:23 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Thu, 25 Sep 2003 11:18:23 +0200 Subject: Xemacs ../ebin and ../include References: <1F42BB97D787C048BCC519FF28048AC304F055@galileo.ifoni.com> Message-ID: > I've been trying for the last hour to convince emacs to tell erl to > output beam files to ../ebin and to use .hrl files in ../include. I think you have to tweak the emacs.el file, to add these parameters to the compile command that is generated when pressing C-c C-k. The simple way is to hardcode them, the diffucult one is to provide a way to set them from Emacs (I wish I knew exactly how myself :-) regards, Vlad From luke@REDACTED Thu Sep 25 12:37:34 2003 From: luke@REDACTED (Luke Gorrie) Date: 25 Sep 2003 12:37:34 +0200 Subject: Xemacs ../ebin and ../include In-Reply-To: References: <1F42BB97D787C048BCC519FF28048AC304F055@galileo.ifoni.com> Message-ID: "Vlad Dumitrescu" writes: > I think you have to tweak the emacs.el file, to add these parameters > to the compile command that is generated when pressing C-c C-k. The > simple way is to hardcode them, the diffucult one is to provide a > way to set them from Emacs (I wish I knew exactly how myself :-) Attached is a patch to erlang.el to make C-c C-k compile into ../ebin if that directory exists, and otherwise use the current directory as usual. I hope I hacked a recent version of erlang.el but I've lost track a bit - let me know if you want help. BTW, personally I prefer to use the Emacs `make' command because it gives nice summaries of compiler errors. I use a small hack so that if there is a Makefile in the directory it runs make, otherwise it just calls erlc to compile the file. The only downside is that the module isn't loaded automatically, but I use Distel for that (C-c C-d L). Here is an example of configuring the `make' command to compile individual Erlang files when there is no Makefile: (defun my-erlang-mode-hook () (make-local-variable 'compile-command) (setq compile-command (if (file-exists-p "Makefile") "make -k" (concat "erlc +debug_info -W " (buffer-file-name))))) (add-hook 'erlang-mode-hook 'my-erlang-mode-hook) For an example of painless Makefiles see the programs in the Jungerl on sourceforge at http://sf.net/projects/jungerl/ Cheers, Luke -------------- next part -------------- A non-text attachment was scrubbed... Name: erlang-outdir.patch Type: text/x-patch Size: 1061 bytes Desc: erlang.el patch to compile into ../ebin/ if it exists URL: From luke@REDACTED Thu Sep 25 14:42:07 2003 From: luke@REDACTED (Luke Gorrie) Date: 25 Sep 2003 14:42:07 +0200 Subject: new syntax - a provocation In-Reply-To: References: Message-ID: Joe Armstrong writes: > Yes - I spent about 10 years thinking about "how to garb the atom > table" just to realise that I'd been thinking about the wrong problem. Surely you considered the (undoubtedly unoriginal) idea that I posted in that time. I'd like to know what's wrong with it - does it badly conflict with the existing ERTS implementation somehow? To restate my idea in terms unlikely to be overlooked, I wrote a working and fully garbage-collectable Atom datatype in about a page of Java (below). Of course, maybe symbolic computing is just easier in Java. My program is not deterministic because it relies on the runtime system to actually collect the garbage. On my computer it works fine, and runs with this output: Equality is okay. There are 3 atoms. After GC there's 1. And it still works after GC. The program: import java.util.*; import java.lang.ref.*; /** * Atom datatype. Use e.g. Atom.get("foobar") to get/create an atom. * Atoms can be tested for equality in unit time using the == operator. * * Atoms and their names are only weakly-referenced internally, and * are therefore able to be garbage collected provided no other * objects reference them. */ public class Atom { // Mapping from names to weakly-referenced Atom objects. // Keys (names) are also weakly referenced. static Map atom_table = new WeakHashMap(); String name; public static Atom get(String name) { synchronized (atom_table) { Reference ref = (Reference)atom_table.get(name); Atom atom = ref == null ? null : (Atom)ref.get(); if (atom == null) { atom = new Atom(name); atom_table.put(name, new WeakReference(atom)); } return atom; } } private Atom(String name) { this.name = name; } // Make atoms remove their names from the table when garbage // collected. This should not be needed in principle, because the // names are only weakly-referenced by the table and should be // garbage collected out of it. However, this isn't happening, and // I think it's because I'm using strings that appear as literals // in the source code and are allocated in the // non-garbage-collected constant pool. public void finalize() { atom_table.remove(this.name); } // Run a simple test when invoked. public static void main(String[] args) { Atom baz = get("baz"); test(); System.out.println("There are " + atom_table.size() + " atoms."); // Create piles and piles of garbage to force a sincere effort // at garbage collection. for (int i = 0; i < 100000000; i++) { new Object(); } System.gc(); System.out.println("After GC there's " + atom_table.size() + "."); if (baz == get("baz")) System.out.println("And it still works after GC."); else System.out.println("But it doesn't work after GC."); } static void test() { Atom foo = get("foo"), foo2 = get("foo"), bar = get("bar"); if ((foo == foo2) && (bar != foo)) System.out.println("Equality is okay."); else System.out.println("Equality broken."); } } From mats.cronqvist@REDACTED Thu Sep 25 15:50:46 2003 From: mats.cronqvist@REDACTED (=?iso-8859-1?Q?Mats_Cronqvist_=28=C4L2/EAB=29?=) Date: Thu, 25 Sep 2003 15:50:46 +0200 Subject: Xemacs ../ebin and ../include Message-ID: <76E5F712842F5F49A35738622BAA0F4F97BF2A@ESEALNT442.al.sw.ericsson.se> here's a snip from my .emacs. when issuing the emacs compile command it does "make -k" if there is a Makefile, otherwise runs "erlc +debug_info -W", adding the -o and/or -I switches if "../ebin" and/or "../inc "exists. apologies for the un-stylish lisp. mats (add-hook 'erlang-mode-hook 'my-erlang-mode-hook) (defun my-erlang-mode-hook () (unless (null buffer-file-name) (make-local-variable 'compile-command) (setq compile-command (if (file-exists-p "Makefile") "make -k" (concat (concat "erlc " (concat (if (file-exists-p "../ebin") "-o ../ebin " "") (if (file-exists-p "../inc") "-I ../inc " "")) "+debug_info -W " buffer-file-name)))))) From c_dhanasekar@REDACTED Thu Sep 25 11:31:31 2003 From: c_dhanasekar@REDACTED (dhanasekaran chenniappan) Date: 25 Sep 2003 09:31:31 -0000 Subject: Dialogic And Erlang Message-ID: <20030925093131.20866.qmail@webmail26.rediffmail.com> An embedded and charset-unspecified text was scrubbed... Name: not available URL: From sn@REDACTED Thu Sep 25 08:58:46 2003 From: sn@REDACTED (Stefan Nickl) Date: Thu, 25 Sep 2003 08:58:46 +0200 (CEST) Subject: essential Erlang In-Reply-To: References: <3F71A4FC.9080806@web.de> Message-ID: On Wed, 24 Sep 2003, Vlad Dumitrescu wrote: > >From your reply I think you misunderstood me. I'll have to be more careful, > it's been a while since using that much English :-) My question referred not > to the Erlang OS, but to breaking apart ERTS and OTP into several loosely > coupled components. Joe did make a case for it, and I tried to propose a > concrete splitting line. Then I began fantasizing :-) What about making them into Linux kernel threads, and making beam known as an executeable format to the kernel? I believe something like that was done with Java a long time ago, but maybe this was only some special case of shebang (#!/path/to/interpreter) CU, SN -- The UNIX equivalent of the "Blue Screen of Death" would be called "kernel panic". It obviously exists, since I have heard and read about it, but I've never been witness to it in my professional career. John Kirch, Networking Consultant and Microsoft Certified Professional (Windows NT) From enano@REDACTED Thu Sep 25 18:10:19 2003 From: enano@REDACTED (Miguel Barreiro Paz) Date: Thu, 25 Sep 2003 18:10:19 +0200 (CEST) Subject: essential Erlang In-Reply-To: References: <3F71A4FC.9080806@web.de> Message-ID: > What about making them into Linux kernel threads, and making beam known > as an executeable format to the kernel? > > I believe something like that was done with Java a long time ago, > but maybe this was only some special case of shebang (#!/path/to/interpreter) IIRC java bytecode was magically recognized as an executable format with a special interpreter and little else. Back then Linux threads were either user-level "green threads" or an early and not too stable implementation of the later clone() based threads. On the latest linux kernels the thread overhead is far, far lower, and the scheduling latency is much better too. But in the C world people still considers 10000 threads to be a "doable but completely insane number". Regards, Miguel From crav@REDACTED Thu Sep 25 15:46:01 2003 From: crav@REDACTED (=?iso-8859-1?Q?Carlos_Rodr=EDguez_Alcal=E1_Villagra?=) Date: Thu, 25 Sep 2003 14:46:01 +0100 Subject: extension mark Message-ID: <001701c3836b$5c596e50$6600a8c0@carlos> I have another answers: If I have this record: -record('AuditDescriptor', { auditToken = asn1_NOVALUE }). % with extension mark How can I use the extension mark????(Sorry if it`s an obvius question) ****************** auditcapabilities(ConnHandle, Events)-> AUD=#'AuditDescriptor'{auditToken="Audit"}, TermId=ui, AUR=#'AuditRequest'{terminationID = TermId, auditDescriptor = AUD}, CR = #'CommandRequest'{command = {auditCapabilities, AUR}}, AR = #'ActionRequest'{contextId = ?megaco_null_context_id, commandRequests = [CR]}, io:format("AR:~p~n", [AR]), {ProtocolVersion, UserReply}=megaco:call(ConnHandle, [AR], []) ******************* With the code that is above, I'll get this, right? MEGACO/1 [172.16.0.1]:2944 Transaction = 1 { Context = - { AuditCapabilities = ui { Audit}}} ***************** but I want this: MEGACO/1 [172.16.0.1]:2944 Transaction = 1 { Context = - { AuditCapabilities = ui { Audit{Events, Signals} }}} And i don`t know how to use the extension mark, could somebody help me?? -------------- next part -------------- An HTML attachment was scrubbed... URL: From crav@REDACTED Thu Sep 25 17:52:33 2003 From: crav@REDACTED (=?iso-8859-1?Q?Carlos_Rodr=EDguez_Alcal=E1_Villagra?=) Date: Thu, 25 Sep 2003 16:52:33 +0100 Subject: megaco package Message-ID: <005e01c3837d$095b87d0$6600a8c0@carlos> I have the megaco_simple_mg and megaco_simple_mgc examples running whitout any changes; I whant that the MGC send any package (for example auditcapabilities) and my package is building without errors (that I think), ... , what I do now? how I can get the ConnHandle variable? I get the ConnHandle variable across a child proces, and this proces sendme back ConnHandle any time when I need. I just have to "call " function , to send AR to MG??,like this: call(ConnHandle, [AR], []) ?????? Thank, Carlos Rodriguez Alcala -------------- next part -------------- An HTML attachment was scrubbed... URL: From csanto@REDACTED Thu Sep 25 22:27:45 2003 From: csanto@REDACTED (Corrado Santoro) Date: Thu, 25 Sep 2003 22:27:45 +0200 Subject: Dialogic And Erlang In-Reply-To: <20030925093131.20866.qmail@webmail26.rediffmail.com> References: <20030925093131.20866.qmail@webmail26.rediffmail.com> Message-ID: <1064521665.3f734fc15ce49@www.cdc.unict.it> Hi, Quoting dhanasekaran chenniappan : > Whether it is possible to communicate with the dll using > erl_ddll: Load_Driver function. erl_ddll module is used to load "Erlang Drivers", i.e. C native functions that you want to call from erlang programs, not to interface a Windows "DLL". I guess that what you need is to write a C driver that provides the needed interface between erlang and the DLL implementing Dialogic API. Another way is to write the C interface by means of "ports" (see documentation) Bye, -Corrado -- ====================================================== Eng. Corrado Santoro, Ph.D. University of Catania - Engineering Faculty Department of Computer Science and Telecommunications Engineering Viale A. Doria, 6 - 95125 CATANIA (ITALY) Tel: +39 095 7382364 Fax: +39 095 338280 EMail: csanto@REDACTED Personal Home Page: http://www.diit.unict.it/users/csanto NUXI Home Page: http://nuxi.iit.unict.it ====================================================== ------------------------------------------------- This mail sent through IMP: http://www.cdc.unict.it/ From ok@REDACTED Fri Sep 26 01:51:36 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Fri, 26 Sep 2003 11:51:36 +1200 (NZST) Subject: new syntax - a provocation Message-ID: <200309252351.h8PNpaP5407732@atlas.otago.ac.nz> Joe Armstrong wrote: For example, for dynamic XML manipulations I dare not represent an XML parse tree as. {AtomTag, [Attr], [Child]} But have to use the horrible form {String, [Attr], [Child]} For fear that one day the atom table will explode :-) I note that SWI Prolog _does_ use atoms for this purpose, even when processing _huge_ RDF files. What's more, SWI Prolog uses atoms for #PCDATA leaves. Perhaps I should also point to the "logix" implementation of Flat Concurrent Prolog. I never actually looked inside, but my understanding was that atoms were implemented basically as free- floating strings, with the added wrinkle that if two atoms were compared and found to be equal, references to one were changed to be references to the other. (Just _which_ references and just _how_ they were found escape my memory. I thought I had a copy of logix on an old file system, but it was a shell script pointing to an installation in Melbourne.) From ok@REDACTED Fri Sep 26 02:19:12 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Fri, 26 Sep 2003 12:19:12 +1200 (NZST) Subject: new syntax - a provocation Message-ID: <200309260019.h8Q0JCtF280244@atlas.otago.ac.nz> Luke Gorrie wrote: Surely you considered the (undoubtedly unoriginal) idea that I posted in that time. I'd like to know what's wrong with it - does it badly conflict with the existing ERTS implementation somehow? To restate my idea in terms unlikely to be overlooked, I wrote a working and fully garbage-collectable Atom datatype in about a page of Java (below). Of course, maybe symbolic computing is just easier in Java. To summarise that code: "use a weak table". Or rather, to summarise the summary: "What's so hard about implementing a garbage collected atom table? Just use a garbage collected atom table to implement it!" Luke Gorrie is right, that _is_ unoriginal. A garbage collected atom table is precisely a weak table; if you already have weak tables (or weak sets, or ...) then implementing a garbage collected atom table is trivial. If you don't, then implementing the one is pretty much identical to implementing the other. In fact this is so unoriginal that it goes back to SNOBOL 4 (and maybe earlier). SNOBOL was (well, I have a running SNOBOL system on my Solaris boxes, so I suppose "is") a language for doing stuff with strings; it would not surprise me if it was the inspiration for the regular expressions used in UNIX. (Not regular expressions in general; I specifically have back-references in mind.) Certainly a version of SNOBOL 3 used to be shipped with UNIX (the program "sno"). SNOBOL programs normally created _lots_ of strings, that's what they were for. But SNOBOL kept all string values in a hash table. A hash table whose elements are retained only if they are referred to elsewhere is precisely a weak table of strings and it is precisely a garbage collected atom table. This is old technology. SWI Prolog has such a thing, and is multithreaded. Java's String.unique() feature presumably uses such a thing. Smalltalk has an atom table, and has concurrent processes, and that's been around since before 1980. I have a Parlog system floating around; I _don't_ have the source code, but I have enough of the .h files for it to be able to tell that it has a global atom table and there are hints in the documentation that it is garbage collected. So we (= "computer scientists in general") know how to implement a global garbage collected atom table in a (uni- or tightly coupled multi-)processor concurrent programming language. BUT we also know that as a shared mutable data structure, access to it requires locking (which Java is just _full_ of; it has taken heroic measures by Java implementors to get locking overheads down to tolerable levels). And we also know that because it is global, it requires some _global_ form of garbage collection. Both of these are Bad Things. It's interesting to consider the question: "what would an Erlang implementation have to be like for us to be able to take a running process and move it to another processor?" (IBM's AIX was able to do this on their mainframes, I believe. I think Kali Scheme can do it. And I think the University of Washington's Emerald could.) Global data structures (global atom atom, global process name registry, global module table) don't really fit nicely into such a scheme. From vances@REDACTED Fri Sep 26 03:38:00 2003 From: vances@REDACTED (Vance Shipley) Date: Thu, 25 Sep 2003 21:38:00 -0400 Subject: Dialogic And Erlang In-Reply-To: <20030925093131.20866.qmail@webmail26.rediffmail.com> References: <20030925093131.20866.qmail@webmail26.rediffmail.com> Message-ID: <20030926013800.GU45604@frogman.motivity.ca> Of the many ways to interface Erlang to foreign language programs the two main ones are linked in drivers and erl_interface. For your case you can probably forget about the linked in driver. For a linked in driver you have to fully cooperate with the Erlang run time system for event handling. Dialogic does not provide a normal device handling mechanism (select/poll) and does not expose real file handles. I'm sure it would be possible to build a layer which would wedge it in there but since it doesn;t fit the paradigm just don't do it. The erl_interface library provides a framework for creating "C-Nodes" which are C language programs which implement enough of the Erlang external distribution protocol to appear as (hidden) nodes in a distributed Erlang system. With this method you have a very clean seperation between the Erlang system and the Dialogic C language environment. They are in fact seperate OS processes communicating using interprocess communication (TCP/IP) and so can also be on seperate machines altogether. [Editorial note: you might want to consider the use of seperate OSes for these two seperate functions. If you are tied to Windows because of the availability of the device drivers for your hardware you may use Windows as the OS for the machine containing the cards and the device drivers while utilizing Linux/FreeBSD/? for the machine running the Erlang node where you will develop your applications. On the other hand if you are tied to Windows for the application side you could employ Linux for the machine containing devices for improved reliability and performance. However remember that it is not neccesary to put these in seperate machines.] The erl_interface application contains two seperate libraries; ei & erl_interface. The latter is deprecated in favour of ei. ei provides you with the functions you will need to decode incoming messages from the Erlang node(s) and to encode messages to the Erlang node(s). You can create an interface which attempts to recreate the Dialogic API on the Erlanng node or you can implement the lowest level of handling in C and communicate higher level application data to Erlang. For example when an event occurs on a device the your program code take some action (i.e. stop playing a voice file), gather some data (run ATDX_TERMMSK()) and send a simple message to Erlang with just the info your application requires. This is often quicker to implement than building the encoding/decoding for all the functions/parameters knowing you'll never use them all. On the other hand you will often make the mistake of implementing in C what you should have done in Erlang simply because you're more familiar with C in which case you will miss out on the productivity gains you can realize working in Erlang. Good luck, -Vance [who has written several Dialogic drivers for Erlang] From ok@REDACTED Fri Sep 26 05:39:29 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Fri, 26 Sep 2003 15:39:29 +1200 (NZST) Subject: Dictionaries Message-ID: <200309260339.h8Q3dTCh286345@atlas.otago.ac.nz> From ok@REDACTED Fri Sep 26 05:57:54 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Fri, 26 Sep 2003 15:57:54 +1200 (NZST) Subject: Dictionaries Message-ID: <200309260357.h8Q3vsgV070736@atlas.otago.ac.nz> Joachim Durchholz wrote: I'd prefer to have keys that are more than atoms. Why, so would I, but you have to start _somewhere_. One important issue is interoperability: using atoms (isomorphic to strings) as keys means interoperability with YAML is straightforward; it means that mapping between some kinds of objects and Erlang is straightforward; it's just exactly right for representing node attributes in XML; ... Atoms are just _enough_ to get most of the benefits. In practice, I'd want the following types of key: * Atoms (if the key space is limited) I don't quite get that. You're not telling me Erlang _still_ has that daft 255-character limit on atom names, are you? Heck, it's nearly 20 years since Quintus made sure the atom limit was at least as big as the host file name limit (1024 on typical UNIX systems). SWI Prolog doesn't have _any_ limit on the size of an atom. * Numbers (I have geographical data, I *need* this *g*) (unlimited-size integers would be fine though) If you have geographical data, you need something better than binary search. You probwably need some kind of R-tree, or at least quad trees. > We'd like these to be compatible with set inclusion. Mixing set semantics with dictionaries is almost sure to give serious trouble. Why on earth should it? Dictionaries *are* sets. It's *failing* to consider set semantics in designing dictionary operations that would give serious trouble. The problem is that, depending on the situation, programmers will want to set dictionaries as different sets: 1) As the set of its keys. 2) As the set of its values. 3) As the set of its key-value pairs. The last one is the mathematical definition of what a dictionary _is_. You can't expect to please everyone, but you _can_ try to make sense. > (1) When we know that something is a dictionary, we can use a more > space-efficient representation. For example, instead of > [{K1,V1},...,{Kn,Vn}] -- (n list cells + n 2-tuples) > we can use > {dict,K1,V1,...,Kn,Vn} -- one 2n+1-tuple (not really a tuple) > which is likely to take somewhat less than half the space. Such a space-efficient representation will be useful iff it is known that the dictionary will not change. Um, this is *Erlang* we're talking about? An Erlang dictionary would not be able to change any more than the number 2 can change. You can compute new dictionaries from old ones. Hmm... yes, the proposal has no way of adding key-value pairs. Yes it does. New_Dict = <{ foo->Bar | Old_Dict }> adds a key (foo)-value (Bar) pair to Old_Dict, giving New_Dict. It just doesn't smash Old_Dict as a side effect. Which leads me to the question how to create a dictionary with an additional key-value pair? Explained in detail in the previous message. Such creation should not have an amortized worse than O(number-of-key-value-pairs * log |Dictionary|) efficiency to be useful. That isn't actually true; when you have enough key-value pairs to worry about you can do it much faster than that if you _don't_ do it one at a time, but yes, there are implementation techniques that do it. One is is one that I've already mentioned, that of changing representations at run time. When you build a new dictionary from an old, the change is done _lazily_. What you get is at first just a description of the change; when the new dictionary is actually _used_, then you make the change. > (2) When we know that something is a dictionary, we can use a more > time-efficient representation. For example, if the keys K1...Kn > as shown above are in standard order, lookups can be done in > O(lg n) time instead of O(n) time. Then the dict implementation could be improved. Simple tree-balancing algorithms that always maintain an amortized O(log |Dictionary|) update and retrieval time exist, even without destructive updates; see Chris Okasaki's "Purely Functional Data Structures". I have seen it. Several of the data structures from that book have even been translated to Erlang. The big point is that "dictionary" does NOT imply "frequently changed dictionary" and it does NOT imply "large dictionary". Things that are dictionaries are also useful when they are small and don't change. We call them records. From ok@REDACTED Fri Sep 26 06:35:43 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Fri, 26 Sep 2003 16:35:43 +1200 (NZST) Subject: dictionaries (was Re: new syntax - a provocation) Message-ID: <200309260435.h8Q4ZhE1067783@atlas.otago.ac.nz> Chris Pressey replied to some of my points: I don't follow _any_ of these arguments. It's my understanding that the representation of dicts is _undefined_. (You didn't go peeking and write code like 'case A of {dict,_,_,...} -> ...', did you? :) It doesn't matter _which_ represenation it is, only that it _has_ a represenation which is ambiguous between "I am a dict" and "I am an Erlang value that just happens to look like dicts currently look". In particular, if I have a list of things which are dicts, there is no way that a UBF encoder can _know_ that they are dicts and encode them appropriately. This could be said for _any_ data structure, which is why one has to pick one's data structures with care. Lists offer incremental construction. Tuples offer O(1) access by number. Dictionaries offer something between O(1) and O(lg n) -- depending on implementation -- access by name. Because the representation of dicts is undefined, they could change anytime in the future, perhaps drastically (e.g. becoming BIFs.) > (1) When we know that something is a dictionary, we can use a more > space-efficient representation. For example, instead of > [{K1,V1},...,{Kn,Vn}] -- (n list cells + n 2-tuples) > we can use > {dict,K1,V1,...,Kn,Vn} -- one 2n+1-tuple (not really a tuple) > which is likely to take somewhat less than half the space. The dict module is written in Erlang. That means it can only use existing Erlang data structures. That limits the range of possibilities that are implementable. > (2) When we know that something is a dictionary, we can use a more > time-efficient representation. For example, if the keys K1...Kn > as shown above are in standard order, lookups can be done in > O(lg n) time instead of O(n) time. Same point as above. This of course applies to any data structure. > (3) When the representation is not visible to the programmer, the > run-time > system may use several different representations. For example, > here are some obvious ones: linear array as shown above, some > kind of binary search tree (so that unchanged chunks can be > shared), some kind of hash table (so that lookup can be O(1)). Because the dict module must use *some* Erlang representation of the data, this possibility (of changing the representation of a value at run time) simply is not available to it. It can pick from several different representations at construction time, sure, but it _can't_, just plain can't, switch representation after construction. Such representation changes are not against the spirit of functional programming, because they don't change the value that is represented; no functional test can detect any change. All that changes is performance. Now, if you are going to rewrite the dict module so that it uses some sort of special internal data structure, all you have to do to get to my proposal is adopt some syntax for these things as well, and why not? > (4) There are lots of "functional array"/"persistent array" > implementations > in the literature which could be used to make setelement/3 take > O(1) time; these could be adapted to make updates to dictionaries > fast too, provided the representation is not exposed. What's not tog et about this? Like the others, it is simply true. (Nearly all of the techniques I have in mind rely on changing a representation at run time after construction, without changing the value which is logically represented.) > (5) With the 'dict' module you get a somewhat less than obvious > textual > representation, which could mean other things. With a built in > data type you can get "just right" textual representation. Prolog has a kluge for this, which is portray/1. By adding clauses portray(empty_dict) :- portray_dict(empty_dict). portray(non_empty_dict(K,V,L,R)) :- portray_dict(non_empty_dict(K,V,L,R)). I can arrange for dictionaries to be printed in a way that makes it clear what they are, _provided_ everyone else knows to avoid the functors in question. Erlang does not have this kluge. It's basically the same point I made earlier: because 'dict' uses *some* Erlang data structures, there is no way for any other code to tell whether a data value really *is* meant to be a dictionary or just *happens* to look like one. In the absence of an always-enforced type system, the only types you can rely on distinguishing are the ones for which there are built-in guard predicates which are guaranteed to be disjoint. > (6) With 'dict' you don't get to do dictionary stuff in patterns or > guards. All that's needed for that is a special _notation_ for dictionaries (which, to be clear, is _not_ the same thing as a _representation_ in this sense.) What's needed is a notation *and* an implementation which is sufficiently good to replace records in everyday use. If you have one, but not the other, you still find yourself wanting records, which may be Erlang's biggest wart. - implement dictionaries directly in BEAM (any number of available C implementations would probably do the trick sufficiently - in fact we already have a very efficient associative storage mechanism that might work just fine. what's it called again? oh yah. 'ETS' :) No, the strength of ETS is *big* dictionaries. Quoting the reference manual, "These provide the ability to store very large amounts of data". These dictionaries are supposed to be small, cheap, fast, immutable. You are supposed to be able to have millions of them. Quoting the ETS manual, "The number of tables stored at one Erlang node is limited. The current default limit is approximately 1400 tables." And, quite disastrously for the intended use of dictionaries, "Note that there is no automatic garbage collection for tables." ETS tables are important and useful, but they are about as far from what we want here as they could possibly be. - map the dict module to BIFs (we don't need a new API for this We don't need a new interface for _that_, but do you really _like_ the existing interface? There were _reasons_ why I proposed a different interface. - add a syntax for pattern-matching dictionaries (the only real advance) Well, if you chop what I propose into two pieces, then suggest implementing the hardest part, then the other half _is_ the only real advance left. Just like if you eat 3/4 of a pie, what's left is only 1/4 of a pie. Using pattern syntax for *constructing* dictionaries is also a large advance. Writing ets2:new(<{name->freddy, type->set, access->protected, keypos->2}>) is clearer than ets2:new([{name,freddy}, {type,set}, {access,protected}, {keypos,2}]) not least because it makes it obvious that the order doesn't matter. Having to write ets2:new(dict:from_list([ {name,freddy}, {type,set}, {access,protected}, {keypos,2}])) would rather miss the point, which is not just to have dictionaries, but to have something principled to use instead of records. From cpressey@REDACTED Fri Sep 26 08:02:50 2003 From: cpressey@REDACTED (Chris Pressey) Date: Thu, 25 Sep 2003 23:02:50 -0700 Subject: dictionaries (was Re: new syntax - a provocation) In-Reply-To: <200309260435.h8Q4ZhE1067783@atlas.otago.ac.nz> References: <200309260435.h8Q4ZhE1067783@atlas.otago.ac.nz> Message-ID: <20030925230250.08a90958.cpressey@catseye.mine.nu> On Fri, 26 Sep 2003 16:35:43 +1200 (NZST) "Richard A. O'Keefe" wrote: > Now, if you are going to rewrite the dict module so that it uses some > sort of special internal data structure, all you have to do to get to > my proposal is adopt some syntax for these things as well, and why > not? That was my point. To summarize: you asked, "Why not use the dict module?" and you gave a bunch of reasons based on the current implementation, and I pointed out that the representation of dicts is undefined - so the implementation of the dict module is _irrelevant_ - so you *can* (and in fact we probably *should* for the sake of easement) use the dict module (**interface**). And in the quoted paragraph above you seem to realize that. Boffo. My work here is done. The rest of your message is commentary that dodges & hovers around that central point. Except for: > We don't need a new interface for _that_, but do you really _like_ > the existing interface? There were _reasons_ why I proposed a > different interface. It's not a matter of me _liking_ it. It's a matter of there being umpteen hundred (thousand?) lines of code already _written_ for it. -Chris From joachim.durchholz@REDACTED Fri Sep 26 10:35:10 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Fri, 26 Sep 2003 10:35:10 +0200 Subject: Dictionaries In-Reply-To: <200309260357.h8Q3vsgV070736@atlas.otago.ac.nz> References: <200309260357.h8Q3vsgV070736@atlas.otago.ac.nz> Message-ID: <3F73FA3E.6000509@web.de> Richard A. O'Keefe wrote: > Joachim Durchholz wrote: > In practice, I'd want the following types of key: > * Atoms (if the key space is limited) > > I don't quite get that. You're not telling me Erlang _still_ has that > daft 255-character limit on atom names, are you? No, but atoms are not garbage collected. The limit is large, but if you have large dictionaries with transient keys, the atom table may fill up. > * Numbers (I have geographical data, I *need* this *g*) > (unlimited-size integers would be fine though) > > If you have geographical data, you need something better than binary > search. You probwably need some kind of R-tree, or at least quad trees. Binary search is enough, thank you :-) All you need to do is to interleave the bits of the coordinates. With that set-up, going down one level in the tree is equivalent to refining the query. Oh, and I need a way to check whether there's any key within a given key range. Unless the dictionary is using hash tables, this is a simple operation. > > We'd like these to be compatible with set inclusion. > > Mixing set semantics with dictionaries is almost sure to give serious > trouble. > > Why on earth should it? Dictionaries *are* sets. It's *failing* to > consider set semantics in designing dictionary operations that would give > serious trouble. > > The problem is that, depending on the situation, programmers > will want to set dictionaries as different sets: > 1) As the set of its keys. > 2) As the set of its values. > 3) As the set of its key-value pairs. > > The last one is the mathematical definition of what a dictionary _is_. > You can't expect to please everyone, but you _can_ try to make sense. Right - but any of the three views above can make sense. Which of them makes sense depends entirely on what the caller wants to do. (I have seen the need for all three views, so I /know/ what I'm speaking about, at least here if not everywhere else *g*.) > One is is one that I've already mentioned, that of changing representations > at run time. When you build a new dictionary from an old, the change is > done _lazily_. What you get is at first just a description of the change; > when the new dictionary is actually _used_, then you make the change. Agreed. > > (2) When we know that something is a dictionary, we can use a more > > time-efficient representation. For example, if the keys K1...Kn > > as shown above are in standard order, lookups can be done in > > O(lg n) time instead of O(n) time. > > Then the dict implementation could be improved. Simple > tree-balancing algorithms that always maintain an amortized O(log > |Dictionary|) update and retrieval time exist, even without destructive > updates; see Chris Okasaki's "Purely Functional Data Structures". > > I have seen it. Several of the data structures from that book have even > been translated to Erlang. > > The big point is that "dictionary" does NOT imply "frequently changed > dictionary" and it does NOT imply "large dictionary". Things that are > dictionaries are also useful when they are small and don't change. We > call them records. Right - and in that case, we don't need a new dictionary type :-) Regards, Jo From joachim.durchholz@REDACTED Fri Sep 26 11:22:29 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Fri, 26 Sep 2003 11:22:29 +0200 Subject: Dictionaries In-Reply-To: <3F73FA3E.6000509@web.de> References: <200309260357.h8Q3vsgV070736@atlas.otago.ac.nz> <3F73FA3E.6000509@web.de> Message-ID: <3F740555.5030103@web.de> Joachim Durchholz wrote: > Richard A. O'Keefe wrote: > >> Joachim Durchholz wrote: >> In practice, I'd want the following types of key: >> * Atoms (if the key space is limited) >> >> I don't quite get that. You're not telling me Erlang _still_ has that >> daft 255-character limit on atom names, are you? > > No, but atoms are not garbage collected. [... reading other posts...] Oh, I see you're thinking about making the atom table garbage-collectable. I agree that this would be preferrable to throwing everything but the kitchen sink into dictionary improvements. Regards, Jo From massimo.cesaro@REDACTED Fri Sep 26 11:26:13 2003 From: massimo.cesaro@REDACTED (Massimo Cesaro) Date: 26 Sep 2003 11:26:13 +0200 Subject: Application under VxWorks - looking for suggestions Message-ID: <1064568375.1975.26.camel@xam> Hello, we'd like to port one of our application to a VxWorks embedded appliance. The system will run on a MIPS CPU based board with up to 16MB of RAM, will be diskless, and will have a 100Mbit Ethernet adapter. The application will be an analog to voip gateway. I'm starting to cross compile Erlang for VxWorks, and I looking for tips and hints to speed from people on the list who maybe already did that. I'm looking for creating a stripped down version of Erlang and OTP (there are a lot of goodies in OTP that I don't need) in order to minimize RAM requirements, and will follow the SAE guidelines for creating a standalone distribution. I see that the biggest chunk in SAE, apart from the BEAM vm is the standard library. Given that I will only use a small subset of stdlib, is it safe to strip down the modules I don't need? Massimo Cesaro From massimo.cesaro@REDACTED Fri Sep 26 17:07:16 2003 From: massimo.cesaro@REDACTED (Massimo Cesaro) Date: 26 Sep 2003 17:07:16 +0200 Subject: erlang and whereever In-Reply-To: <004501c381b1$9f9ae970$6600a8c0@carlos> References: <004501c381b1$9f9ae970$6600a8c0@carlos> Message-ID: <1064588838.1937.34.camel@xam> Hello, I was successful using Audiocodes MP 104 and MP 108 gateways. The Megaco stack out of the box requires a minimal patch because of the different handling of \n by the Audiocodes stuff, but apart from this they work pretty well together. Cheers, Massimo On Tue, 2003-09-23 at 11:03, Carlos Rodr?guez Alcal? Villagra wrote: > I would like to know if anyone has tried the Erlang's Megaco Libraries with the MAX TNT version 10.1.0 Gateway from Lucent. > Or, with any other Gateway of Lucent? > > > From per@REDACTED Fri Sep 26 19:42:16 2003 From: per@REDACTED (Per Bergqvist) Date: Fri, 26 Sep 2003 20:42:16 +0300 Subject: extension mark In-Reply-To: <001701c3836b$5c596e50$6600a8c0@carlos> Message-ID: <200309261842.h8QIgG114779@tessla.levonline.com> You can't. everything after an ellipsis is ignored by the decoder. I proposed earlier this year that the extension data should be stored in a special '$ellipsis' field. If we are lucky it will be there in a future release ... /Per ------------------- > I have another answers: > If I have this record: > > -record('AuditDescriptor', > { > auditToken = asn1_NOVALUE > }). % with extension mark > > How can I use the extension mark????(Sorry if it`s an obvius question) > > ****************** > auditcapabilities(ConnHandle, Events)-> > AUD=#'AuditDescriptor'{auditToken="Audit"}, > TermId=ui, > AUR=#'AuditRequest'{terminationID = TermId, auditDescriptor = AUD}, > CR = #'CommandRequest'{command = {auditCapabilities, AUR}}, > AR = #'ActionRequest'{contextId = ?megaco_null_context_id, commandRequests = [CR]}, > io:format("AR:~p~n", [AR]), > {ProtocolVersion, UserReply}=megaco:call(ConnHandle, [AR], []) > > ******************* > With the code that is above, I'll get this, right? > MEGACO/1 [172.16.0.1]:2944 > Transaction = 1 { > Context = - { > AuditCapabilities = ui { > Audit}}} > ***************** > but I want this: > MEGACO/1 [172.16.0.1]:2944 > Transaction = 1 { > Context = - { > AuditCapabilities = ui { > Audit{Events, Signals} > }}} > > And i don`t know how to use the extension mark, could somebody help me?? > ========================================================= Per Bergqvist Synapse Systems AB Phone: +46 709 686 685 Email: per@REDACTED From erlang@REDACTED Fri Sep 26 16:57:42 2003 From: erlang@REDACTED (Inswitch Solutions - Erlang Evaluation) Date: Fri, 26 Sep 2003 16:57:42 +0200 Subject: Load Balancing Message-ID: <01a501c3843e$8a8b0030$1e00a8c0@design> Does anyone know if there is an implementation of load-balancing between processes in Erlang? I think I have seen a function in Erlang that sends a message to the process which has less work in progress. Right? Thanks, Eduardo Figoli INSwitch Solutions -------------- next part -------------- An HTML attachment was scrubbed... URL: From crav@REDACTED Fri Sep 26 19:22:48 2003 From: crav@REDACTED (=?iso-8859-1?Q?Carlos_Rodr=EDguez_Alcal=E1_Villagra?=) Date: Fri, 26 Sep 2003 18:22:48 +0100 Subject: megaco_tcp Message-ID: <006701c38452$cffe9aa0$6600a8c0@carlos> In the megaco_simple_mg and megaco_simple_mgc files once the mg gets to the start_transport, It gets a Connhandled . Can I use a Connhandle more than one time, for example, for calling the function service_change(ConnHndle) twice?? Or do I have to Create a "new" Connhanled for every transaction? Because I tried to send two transactions and I didn't receive the second on the other side. It didn't give me an error message though. Does that mean that the conection ended? thank bye -------------- next part -------------- An HTML attachment was scrubbed... URL: From ok@REDACTED Mon Sep 29 01:24:50 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Mon, 29 Sep 2003 11:24:50 +1200 (NZST) Subject: dictionaries (was Re: new syntax - a provocation) Message-ID: <200309282324.h8SNOo8H067755@atlas.otago.ac.nz> Chris Pressey continues to insist on missing the point. To summarize: you asked, "Why not use the dict module?" and you gave a bunch of reasons based on the current implementation, and I pointed out that the representation of dicts is undefined - so the implementation of the dict module is _irrelevant_ - so you *can* (and in fact we probably *should* for the sake of easement) use the dict module (**interface**). Imagine a frustrated scream here. My proposal is just plain *INDEPENDENT* of the dict module. It's a historical accident that there IS a dict module. My proposal is not intended as a replacement for the dict module. THERE IS NOTHING TO BE GAINED BY IMITATING AN OLD BAD INTERFACE. And in the quoted paragraph above you seem to realize that. Boffo. My work here is done. The rest of your message is commentary that dodges & hovers around that central point. Except for: > We don't need a new interface for _that_, but do you really _like_ > the existing interface? There were _reasons_ why I proposed a > different interface. It's not a matter of me _liking_ it. It's a matter of there being umpteen hundred (thousand?) lines of code already _written_ for it. What in the name of sanity has that got to do with anything? I have never proposed that the 'dict' module be withdrawn or changed in any way. It is Chris Pressey who suggested changing it. I don't *CARE* how much code uses the 'dict' module (except to feel sorry for the people who wrote that code) because I AM NOT SUGGESTING ANY CHANGE WHATSOEVER IN THE SLIGHTEST to the 'dict' module. It is an imporant fact about the dict module that it *has* an implementation in Erlang, which means that it uses Erlang data structures, which means that it cannot be used to implement a new kind of primitive data structure. If you change it to use a new primitive data structure, THAT WILL BE AN INCOMPATIBLE CHANGE. That's not my suggestion at all. I have suggested (and it turns out that Joe Armstrong has also suggested) a new *primitive* data structure for Erlang. Putzing around with the 'dict' module would IN NO WAY simplify the implementation of that new primitive data structure, while there are ways in which it could break existing working code. Y'know, I was careful *not* to use the name 'dict' for these things. I did have good reasons. "Dictionaries" are not "dicts" are not "dictionaries". They are obviously similar, but they are DIFFERENT, and independent. There is no reason whatsoever why dictionaries should have the same interface as dicts, and many reasons why they should not. From ok@REDACTED Mon Sep 29 05:13:32 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Mon, 29 Sep 2003 15:13:32 +1200 (NZST) Subject: length() in guards Message-ID: <200309290313.h8T3DWlt102297@atlas.otago.ac.nz> One of the perennial questions about Erlang is "can't we generalise guards to allow any expression?" The standard response is that the guard tests and expressions are supposed to have certain properties. And the standard retort to that is that length/1 does't have them. A tiny restriction would tame length/1 in guards. The restriction is "a call to length/1 may appear in a guard only as an entire operand of a comparison (==, /=, <, >=, >, <=, =:=, -/=) in which the other operand is not a call to length/1". So length(X) == 4 would be allowed, but length(X)*2 == 8 would not be allowed. This helps because computing length(X) requires time proportional to the length of X, while computing length(X) N, where N is an integer, requires time O(max(1,N)). For example, the guard test length(X) /= 2 can be evaluated in O(1) time, no matter how long X is. Poking around in the Erlang sources, I've found that the majority of uses of length/1 in a guard are equivalent to length() ( | | size()) There are some exceptions. There's a use of when length() > length() that not only could be expressed without doing that, but would be O(N) instead of O(N**2) if so expressed. There's a use of when length() == length() guarding a call to a function so that 'false' can be returned if the lists aren't the same length, BUT that function would return 'false' anyway in that case, AND is actually a loop invariant, so the module doesn't really need to do this and would be faster if it didn't. There's a function f(E, F, [], false) when length(E) + length(F) == 8 -> list_to_tuple(reverse(E) ++ reverse(F)); f(E, F, [D,C,B,A], false) when length(E) + length(F) == 6 -> list_to_tuple(reverse(E) ++ reverse(F) ++ [A*256+B, C*256+D]); f(E, F, [], true) when length(E)+length(F) =< 8 -> list_to_tuple(reverse(E) ++ zero(8-(length(E)+length(F))) ++ reverse(F)); f(E, F, [D,C,B,A], true) when length(E)+length(F) =< 6 -> list_to_tuple(reverse(E) ++ zero(6-(length(E)+length(F))) ++ reverse(F) ++ [A*256+B, C*256+D]). which could be written as f(E, F, X, B) -> list_to_tuple(f(E, F, X, B, length(E)+length(F))). f(E, F, [], false, 8) -> reverse(E) ++ reverse(F); f(E, F, [D,C,B,A], false, 6) -> reverse(E) ++ reverse(F) ++ [A*256+B,C*256+D]; f(E, F, [], true, N) when N =< 8 -> reverse(E) ++ zero(8-N) ++ reverse(F); f(E, F, [D,C,B,A], true, N) when N =< 6 -> reverse(E) ++ zero(6-N) ++ reverse(F) ++ [A*256+B,C*256+D]. There's a when + length() that could be when length() - There's a function f(X, Y) -> case lists:prefix(X, Y#field) of true when length(Y#field) > length(X) -> g(X, Y); false -> above end. which could simply be f(X, Y) -> case lists:proper_prefix(X, Y#field) of true -> g(X, Y); false -> above end. if only the lists module included proper_prefix([X|Prefix], [X|List]) -> proper_prefix(Prefix, List); proper_prefix([], [_|_]) -> true; proper_prefix(_, _) -> false. which it should anyway. When we look at g/2, we find g(X, Y) when length(Y#field) == length(X) + 1 -> ; g(X, Y) when length(Y#field) > length(X) + 1 -> . So this pair of functions could be f(X, Y) -> Delta = length(Y#field) - length(X), case lists:prefix(X, Y#field) of true when Delta > 0 -> g(X, Y, Delta); false -> above end. g(X, Y, Delta) when Delta == 1 -> ; g(X, Y, Delta) when Delta > 1 -> . There's also a function f(X, Y) when length(X) == length(Y) -> ; f(X, Y) when length(X) > length(Y) -> ; f(X, Y) when length(X) < length(Y) -> . This is obviously inefficient; it could so easily have been f(X, Y) -> Delta is length(X) - length(Y), if Delta < 0 -> ; Delta > 0 -> ; Delta ==0 -> end. So everywhere I look, either the guards already conform to this restriction, or the code would be more efficient if it did conform, and could be at least as clear. What do people think? From cpressey@REDACTED Mon Sep 29 07:26:17 2003 From: cpressey@REDACTED (Chris Pressey) Date: Sun, 28 Sep 2003 22:26:17 -0700 Subject: dictionaries (was Re: new syntax - a provocation) In-Reply-To: <200309282324.h8SNOo8H067755@atlas.otago.ac.nz> References: <200309282324.h8SNOo8H067755@atlas.otago.ac.nz> Message-ID: <20030928222617.3607254f.cpressey@catseye.mine.nu> On Mon, 29 Sep 2003 11:24:50 +1200 (NZST) "Richard A. O'Keefe" wrote: > Chris Pressey continues to insist on > missing the point. > To summarize: you asked, "Why not use the dict module?" and > you gave a bunch of reasons based on the current implementation, > and I pointed out that the representation of dicts is undefined > - so the implementation of the dict module is _irrelevant_ - so > you *can* (and in fact we probably *should* for the sake of > easement) use the dict module (**interface**). > > Imagine a frustrated scream here. Okay. > My proposal is just plain *INDEPENDENT* of the dict module. > It's a historical accident that there IS a dict module. > My proposal is not intended as a replacement for the dict module. > > THERE IS NOTHING TO BE GAINED BY IMITATING AN OLD BAD INTERFACE. Forwards-compatibility...? Zero or near-zero retraining...? PoLA...? Occam's Razor as it applies to software engineering ("do not multiply interfaces unnecessarily")...? For that matter, why do you call the dict interface "bad"? > And in the quoted paragraph above you seem to realize that. > Boffo. My work here is done. The rest of your message is > commentary that dodges & hovers around that central point. > Except for: > > > We don't need a new interface for _that_, but do you really > > _like_ the existing interface? There were _reasons_ why I > > proposed a different interface. > > It's not a matter of me _liking_ it. It's a matter of there > being umpteen hundred (thousand?) lines of code already > _written_ for it. > > What in the name of sanity has that got to do with anything? See above. > I have never proposed that the 'dict' module be withdrawn or changed > in any way. It is Chris Pressey who suggested changing it. Yes, I *am* suggesting that! Changing the *implementation*. Everything else - the interface, the documentation - should stay the same. > I don't *CARE* how much code uses the 'dict' module (except to feel > sorry for the people who wrote that code) because I AM NOT SUGGESTING > ANY CHANGE WHATSOEVER IN THE SLIGHTEST to the 'dict' module. Yes, I know! That's why I'm *adding* that suggestion to your proposal. (Except where I don't agree with your proposal, of course - specifically, I see no reason for dictionary keys to be limited to atoms. There also seems to be some minor confusion around whether keys are ordered or not - I can't see why they should be, and you did not state that they should be nor propose 'next key'- and 'previous key'- style operations on them that would suggest that they are, but your dictionary_to_list operation does for some reason define that the result is ordered.) > It is an imporant fact about the dict module that it *has* an > implementation in Erlang, which means that it uses Erlang data > structures, which means that it cannot be used to implement a new kind > of primitive data structure. No, that is wrong. The fact that the dict module has an implementation in Erlang is not important, as you claim, but it is, to borrow a phrase from you, a "historial accident." An artefact. Something that you need not even be aware of to use the dict module 100% properly. There is *nothing* about the dict module that requires that it be implemented as Erlang code. > If you change it to use a new primitive data structure, > THAT WILL BE AN INCOMPATIBLE CHANGE. That's not my suggestion at all. It will *not* be an incompatible change. The man page clearly states: "Dict implements a Key - Value dictionary. The representation of a dictionary is not defined." Therefore, the representation may be changed. Any code that relies on a particular representation is *already broken*. This is the very essence of why anyone would even consider establishing a contract like this in the first place. Even if the OTP team is so paranoid as to cater to every irresponsibly written crap-hack out there which makes assumptions about what it was explicitly told NOT to make assumptions about - ignoring for the moment the disingenuousness entailed in giving a condition which one does not expect others to adhere to - it *still* behooves them to provide an identical interface for any new dictionary module, to make migrating existing code easier. The orddict module can even be seen as setting a precedent of a sort in this regard. I'm not certain there's any code out there that looks like Module = case X of 1 -> dict; 2 -> orddict end, D = Module:from_list([{{0, 0}, hello_world}]). but because the interface is shared, it's certainly not out of the question, and is, in fact, a reason to keep using the same interface for *other* dictionary-implementing modules. Not that there is any reason to make another module! The bottom line is that Ericsson can make whatever changes they want to the dict module - so long as it continues to do what it says it does - and because they had the foresight to include those magic words "The representation of a dictionary is not defined" in the man page, no one has *any* right to complain when it's no longer a tuple like {dict,Size,Etc,Etc,Etc}. > I have suggested (and it turns out that Joe Armstrong has also > suggested) a new *primitive* data structure for Erlang. As have I, in the past. But it's a moot point here - *if* such a new primitive data structure is a dictionary there's *still* no reason that the dict module can't be the interface for it. Further, to me, adding a new data type to Erlang is very much a seperate issue from adding better dictionaries to Erlang. I'll try to explain why: My proposal for improving Erlang's notion of data structuring (at the moment - I've considered several variations but this is the one that has had the most lasting appeal to me) is that it should be possible to given any value of any type a 'genus' (essentially just a tagname, much like Perl's 'bless' mechanism,) by which it may be matched on in guards and such without examining its structure in any way. Joe's proposal is similar, but all such named things in his scheme must be structs. Your proposal, as I understand it, is that dictionaries are opaque insofar as they are a seperate primitive, like lists - but (also like lists) they do not have specific names, so while it is possible to distinguish a dictionary from any other data type, there is no way to distinguish between different 'kinds' of dictionaries aside from matching on a key or value that you know, by convention, should be present. Much like tagged tuples today. Is this a fair assessment of our respective proposals? I prefer my proposal because it doesn't tie the programmer to one particular representation. If they want to pass, say, 'employee' data to code that doesn't need to (and in fact shouldn't) be aware of the internals of it, they can implement each 'employee' as a record, a dictionary, a property list, a string, a pid, or a reference, or whatever else, as they see fit - and they can decide to change it later without breaking that other code. That other code can still test to see if a value is an 'employee' or not with a guard test something like genus(A) == employee ...without having to know anything about the structure of A. With Joe's proposal or yours, an 'employee' would have to be represented by (or at least wrapped in) a struct or a dictionary, respectively. In Joe's case, other code could tell that A is an employee with a guard test something like is_struct(A, employee) In your case, other code would have to determine that A is an employee by something like dictionary_has(A, employee_id) Either of these two ways, you end up knowing that A is a struct or a dictionary. Which is, frankly, more than you need to know. That said, I see nothing wrong with improving Erlang's ability to structure data in dictionaries, either, and I assumed (reasonably, I thought) that that, rather than typing, was the main thrust of your proposal. > Putzing around with the'dict' module would IN NO WAY simplify the > implementation of that new primitive data structure, No, but using it as the implementation of the dict module would simplify the *adoption* of that data structure by Erlang programmers. Because chances are they're already familiar with the dict interface. If it ain't broke, don't fix it. And the dict interface ain't broke. > while there are ways in which it could break existing working code. Existing *incorrect* code that violates contract. The fact that it may work is, again as you put it, an accident. > Y'know, I was careful *not* to use the name 'dict' for these things. > I did have good reasons. "Dictionaries" are not "dicts" are not > "dictionaries". They are obviously similar, but they are DIFFERENT, > and independent. There is no reason whatsoever why dictionaries > should have the same interface as dicts, and many reasons why they > should not. I've given four reasons why dictionaries should have the same interface as dicts in my second paragraph in this message. The only reasonable reason I can see for why they should not is if they are limited to having only atoms as their keys - and I do not see much value in such crippled dictionaries. -Chris From Bengt.Kleberg@REDACTED Mon Sep 29 09:00:03 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Mon, 29 Sep 2003 09:00:03 +0200 Subject: Load Balancing In-Reply-To: <01a501c3843e$8a8b0030$1e00a8c0@design> References: <01a501c3843e$8a8b0030$1e00a8c0@design> Message-ID: <3F77D873.8010602@ericsson.com> Inswitch Solutions - Erlang Evaluation wrote: > > Does anyone know if there is an implementation of load-balancing between > processes in Erlang? > I think I have seen a function in Erlang that sends a message to the > process which has less work in progress. Right? there is (afaik) no such feature in erlang. somebody might have made one. but is is not present on http://www.erlang.org/user.html bengt From Bengt.Kleberg@REDACTED Mon Sep 29 09:41:16 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Mon, 29 Sep 2003 09:41:16 +0200 Subject: length() in guards In-Reply-To: <200309290313.h8T3DWlt102297@atlas.otago.ac.nz> References: <200309290313.h8T3DWlt102297@atlas.otago.ac.nz> Message-ID: <3F77E21C.9060607@ericsson.com> Richard A. O'Keefe wrote: > One of the perennial questions about Erlang is "can't we generalise > guards to allow any expression?" The standard response is that the > guard tests and expressions are supposed to have certain properties. > And the standard retort to that is that length/1 does't have them. > > A tiny restriction would tame length/1 in guards. > The restriction is > "a call to length/1 may appear in a guard only as an entire > operand of a comparison (==, /=, <, >=, >, <=, =:=, -/=) > in which the other operand is not a call to length/1". > ...deleted > What do people think? what about: is_length_equal( Var, Length ) is_length_greater( Var, Length ) is_length_less( Var, Length ) this would make it easier to remember, imho. bengt From vlad_dumitrescu@REDACTED Mon Sep 29 09:54:50 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Mon, 29 Sep 2003 09:54:50 +0200 Subject: Load Balancing References: <01a501c3843e$8a8b0030$1e00a8c0@design> <3F77D873.8010602@ericsson.com> Message-ID: > Inswitch Solutions - Erlang Evaluation wrote: > > > > Does anyone know if there is an implementation of load-balancing between > > processes in Erlang? Just one quick thought. Load balancing between processes on the same node is not really very useful (please someone correct me if I am wrong) - the assumption being that the work being done isn't mostly sitting idle. This is because CPU is still shared and if all processes want 90% of it.... What is more useful is load balancing between nodes. regards, Vlad From Bengt.Kleberg@REDACTED Mon Sep 29 10:17:05 2003 From: Bengt.Kleberg@REDACTED (Bengt Kleberg) Date: Mon, 29 Sep 2003 10:17:05 +0200 Subject: Load Balancing In-Reply-To: References: <01a501c3843e$8a8b0030$1e00a8c0@design> <3F77D873.8010602@ericsson.com> Message-ID: <3F77EA81.5030005@ericsson.com> Vlad Dumitrescu wrote: >>Inswitch Solutions - Erlang Evaluation wrote: >> ...deleted > Just one quick thought. Load balancing between processes on the same node is > not really very useful (please someone correct me if I am wrong) - the if one user thread can have many kernel threads it should be possible for the erlang node to use several cpus. imho. bengt From vlad_dumitrescu@REDACTED Mon Sep 29 11:16:41 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Mon, 29 Sep 2003 11:16:41 +0200 Subject: Load Balancing References: <01a501c3843e$8a8b0030$1e00a8c0@design> <3F77D873.8010602@ericsson.com> <3F77EA81.5030005@ericsson.com> Message-ID: From: "Bengt Kleberg" > Vlad Dumitrescu wrote: > >>Inswitch Solutions - Erlang Evaluation wrote: > >> > ...deleted > > Just one quick thought. Load balancing between processes on the same node is > > not really very useful (please someone correct me if I am wrong) - the > > if one user thread can have many kernel threads it should be possible > for the erlang node to use several cpus. imho. Yes, I agree but as far as I know this is not the case. See http://www.erlang.org/ml-archive/erlang-questions/200209/msg00071.html /Vlad From raimo@REDACTED Mon Sep 29 13:32:13 2003 From: raimo@REDACTED (Raimo Niskanen) Date: Mon, 29 Sep 2003 13:32:13 +0200 Subject: length() in guards References: <200309290313.h8T3DWlt102297@atlas.otago.ac.nz>, <3F77E21C.9060607@ericsson.com> Message-ID: We have already thought of a possible optimization in the compiler to convert such as "length(L) > 3" to an internal "length_gt(L, 3)", but it was not possible without changing the semantics of length(L). Reason: if L is an improper list, length(L) crashes, so the guard test length(L) must fail, hence the guard test must search to the end of the list. Changing the semantics of (or putting restrictions on) length(L) is not something we are very keen on (to put it mildly). Introducing is_length_gt(List, Length) and such with different semantics than length(List) for improper lists does at least not break (the sacred) backwards compatibility. -- / Raimo Niskanen, Erlang/OTP, Ericsson AB Bengt Kleberg wrote: > Richard A. O'Keefe wrote: > >> One of the perennial questions about Erlang is "can't we generalise >> guards to allow any expression?" The standard response is that the >> guard tests and expressions are supposed to have certain properties. >> And the standard retort to that is that length/1 does't have them. >> >> A tiny restriction would tame length/1 in guards. >> The restriction is >> "a call to length/1 may appear in a guard only as an entire >> operand of a comparison (==, /=, <, >=, >, <=, =:=, -/=) >> in which the other operand is not a call to length/1". >> > ...deleted > > > What do people think? > > what about: > > is_length_equal( Var, Length ) > is_length_greater( Var, Length ) > is_length_less( Var, Length ) > > this would make it easier to remember, imho. > > > bengt > From joachim.durchholz@REDACTED Mon Sep 29 13:42:19 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Mon, 29 Sep 2003 13:42:19 +0200 Subject: dictionaries (was Re: new syntax - a provocation) In-Reply-To: <20030928222617.3607254f.cpressey@catseye.mine.nu> References: <200309282324.h8SNOo8H067755@atlas.otago.ac.nz> <20030928222617.3607254f.cpressey@catseye.mine.nu> Message-ID: <3F781A9B.60304@web.de> Chris Pressey wrote: > Richard A. O'Keefe wrote: >>If you change it to use a new primitive data structure, >>THAT WILL BE AN INCOMPATIBLE CHANGE. That's not my suggestion at all. > > It will *not* be an incompatible change. The man page clearly states: > > "Dict implements a Key - Value dictionary. The representation of a > dictionary is not defined." > > Therefore, the representation may be changed. Any code that relies on a > particular representation is *already broken*. This is the very essence > of why anyone would even consider establishing a contract like this in > the first place. Um... while I agree that any code that relies on the internal implementation should be considered broken, there's still the question whether those bugs should be exposed or covered. Personally, I think it's a case of "never change a running system", but anybody's mileage may vary, and I'm certainly in no position to advise one way or the other. However, I do think that the discussion exposes clearly why opaque data types are important: if the dict implementation hadn't exposed its internals, there would be no possibility of client code relying on those internals, and the entire discussion would not have started in the first place. Personally, I think that opaque data types should also interact with pattern matching, i.e. there should also be "deconstructors". For example, the Dictionary type should have something like a [H|R] "destructor" that gave me the first pair (H) and the rest of the dictionary (R), so that I can pattern match as in [(Key, Value)|R]->... > Not that there is any reason to make another module! The bottom line is > that Ericsson can make whatever changes they want to the dict module > - so long as it continues to do what it says it does - and because they > had the foresight to include those magic words "The representation of a > dictionary is not defined" in the man page, no one has *any* right to > complain when it's no longer a tuple like {dict,Size,Etc,Etc,Etc}. The issue isn't complaints. The issue is how much software will break (hopefully little), how much effort it will take to fix it (which is a question of how easy it is to find code that makes assumptions on internals), and what consequences the uncaught bugs will have (which is something that's quite difficult to predict). The complaints won't be about dict, they will be about misbehaving AXP switches and similar stuff... Regards, Jo From cpressey@REDACTED Mon Sep 29 17:47:33 2003 From: cpressey@REDACTED (Chris Pressey) Date: Mon, 29 Sep 2003 08:47:33 -0700 Subject: dictionaries (was Re: new syntax - a provocation) In-Reply-To: <3F781A9B.60304@web.de> References: <200309282324.h8SNOo8H067755@atlas.otago.ac.nz> <20030928222617.3607254f.cpressey@catseye.mine.nu> <3F781A9B.60304@web.de> Message-ID: <20030929084733.28fed3d4.cpressey@catseye.mine.nu> On Mon, 29 Sep 2003 13:42:19 +0200 Joachim Durchholz wrote: > Chris Pressey wrote: > > Richard A. O'Keefe wrote: > >>If you change it to use a new primitive data structure, > >>THAT WILL BE AN INCOMPATIBLE CHANGE. That's not my suggestion at > >all. > > > > It will *not* be an incompatible change. The man page clearly > > states: > > > > "Dict implements a Key - Value dictionary. The representation of a > > dictionary is not defined." > > > > Therefore, the representation may be changed. Any code that relies > > on a particular representation is *already broken*. This is the > > very essence of why anyone would even consider establishing a > > contract like this in the first place. > > Um... while I agree that any code that relies on the internal > implementation should be considered broken, there's still the question > whether those bugs should be exposed or covered. > Personally, I think it's a case of "never change a running system", > but anybody's mileage may vary, and I'm certainly in no position to > advise one way or the other. > > However, I do think that the discussion exposes clearly why opaque > data types are important: if the dict implementation hadn't exposed > its internals, there would be no possibility of client code relying on > those internals, and the entire discussion would not have started in > the first place. Yes. Definately. > Personally, I think that opaque data types should also interact with > pattern matching, i.e. there should also be "deconstructors". For > example, the Dictionary type should have something like a [H|R] > "destructor" that gave me the first pair (H) and the rest of the > dictionary (R), so that I can pattern match as in [(Key, > Value)|R]->... Well - maybe, but I don't see how it really fits in with the opacity - if you're not supposed to know anything about the structure of some value, then you probably shouldn't be taking it apart yourself, even in an abstract way. It would be better to let the type's interface take it apart for you - and yes, better still if that could be integrated with pattern matching (like if the type could describe how it is to behave during a pattern matching operation) - but that might open a whole new can of worms with types having "surface representations" (where, say, a dictionary, or an employee, *looks* like, say, a list, w.r.t. pattern matching, but has some completely other representation internally.) That sounds both extremely clever, and like a breeding ground for confusion. Who was it that said data abstraction and pattern matching are polar opposites...? > > Not that there is any reason to make another module! The bottom > > line is that Ericsson can make whatever changes they want to the > > dict module- so long as it continues to do what it says it does - > > and because they had the foresight to include those magic words "The > > representation of a dictionary is not defined" in the man page, no > > one has *any* right to complain when it's no longer a tuple like > > {dict,Size,Etc,Etc,Etc}. > > The issue isn't complaints. The issue is how much software will break > (hopefully little), how much effort it will take to fix it (which is a > question of how easy it is to find code that makes assumptions on > internals), and what consequences the uncaught bugs will have (which > is something that's quite difficult to predict). > The complaints won't be about dict, they will be about misbehaving AXP > switches and similar stuff... My guess would be that there would be none... but perhaps I have an unwarranted amount of faith in the idea that the great majority of paid Erlang programmers aren't idiots. At any rate, if something explicitly undefined, like the representation of dicts, can't change, then I'm afraid we'll have to completely give up Joe's ideal of throwing other stuff (like records) out of Erlang, once better things are added. It will simply never happen. More incentive to start fresh with a completely new language, probably. > Regards, > Jo -Chris From joachim.durchholz@REDACTED Mon Sep 29 18:36:02 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Mon, 29 Sep 2003 18:36:02 +0200 Subject: Opaque types (was: dictionaries, was: new syntax - a provocation) In-Reply-To: <20030929084733.28fed3d4.cpressey@catseye.mine.nu> References: <200309282324.h8SNOo8H067755@atlas.otago.ac.nz> <20030928222617.3607254f.cpressey@catseye.mine.nu> <3F781A9B.60304@web.de> <20030929084733.28fed3d4.cpressey@catseye.mine.nu> Message-ID: <3F785F72.6030201@web.de> Chris Pressey wrote: > Joachim Durchholz wrote: > >> Personally, I think that opaque data types should also interact >> with pattern matching, i.e. there should also be "deconstructors". >> For example, the Dictionary type should have something like a [H|R] >> "destructor" that gave me the first pair (H) and the rest of the >> dictionary (R), so that I can pattern match as in [(Key, >> Value)|R]->... > > Well - maybe, but I don't see how it really fits in with the opacity > - if you're not supposed to know anything about the structure of some > value, then you probably shouldn't be taking it apart yourself, even > in an abstract way. The key is that the designer of the type defines in which ways it should be taken apart. For example, a Customer data type could have different "views": Customer_by_address (Name, Nr, Street, Town, ...) Customer_by_standing (Name, Nr, ABC) Customer_by_history (Name, Nr, Transaction_List) The nice thing here would be that it would be possible to extend the Customer data type without having to rewrite all the code that does pattern matching on Customer data, as long as the new data didn't show up in the new views. > It would be better to let the type's interface take it apart for you > - and yes, better still if that could be integrated with pattern > matching (like if the type could describe how it is to behave during > a pattern matching operation) - but that might open a whole new can > of worms with types having "surface representations" (where, say, a > dictionary, or an employee, *looks* like, say, a list, w.r.t. pattern > matching, but has some completely other representation internally.) > That sounds both extremely clever, and like a breeding ground for > confusion. Who was it that said data abstraction and pattern > matching are polar opposites...? Well, that's what I meant. I think :-) >>> Not that there is any reason to make another module! The bottom >>> line is that Ericsson can make whatever changes they want to the >>> dict module- so long as it continues to do what it says it does - >>> and because they had the foresight to include those magic words >>> "The representation of a dictionary is not defined" in the man >>> page, no one has *any* right to complain when it's no longer a >>> tuple like {dict,Size,Etc,Etc,Etc}. >> >> The issue isn't complaints. The issue is how much software will >> break (hopefully little), how much effort it will take to fix it >> (which is a question of how easy it is to find code that makes >> assumptions on internals), and what consequences the uncaught bugs >> will have (which is something that's quite difficult to predict). >> The complaints won't be about dict, they will be about misbehaving >> AXP switches and similar stuff... > > > My guess would be that there would be none... but perhaps I have an > unwarranted amount of faith in the idea that the great majority of > paid Erlang programmers aren't idiots. Not idiots. Just programmers who have to make everyday compromises between quality and time-to-market. > At any rate, if something explicitly undefined, like the > representation of dicts, can't change, then I'm afraid we'll have to > completely give up Joe's ideal of throwing other stuff (like records) > out of Erlang, once better things are added. It will simply never > happen. More incentive to start fresh with a completely new > language, probably. Well, language tuning has never been a particularly rewarding job... Regards, Jo From luke@REDACTED Mon Sep 29 19:07:39 2003 From: luke@REDACTED (Luke Gorrie) Date: 29 Sep 2003 19:07:39 +0200 Subject: new syntax - a provocation In-Reply-To: <200309260019.h8Q0JCtF280244@atlas.otago.ac.nz> References: <200309260019.h8Q0JCtF280244@atlas.otago.ac.nz> Message-ID: "Richard A. O'Keefe" writes: > So we (= "computer scientists in general") know how to implement a global > garbage collected atom table in a (uni- or tightly coupled multi-)processor > concurrent programming language. No worries then, that's what Erlang is! > It's interesting to consider the question: "what would an Erlang > implementation have to be like for us to be able to take a running > process and move it to another processor?" (IBM's AIX was able to > do this on their mainframes, I believe. I think Kali Scheme can do it. And also the question: why would you want to? Seriously. Kali Scheme looks extremely complex and subtle to me. In Kali you can capture a process and send it to another machine, and it will magically transport the related code on-demand, do distributed garbage collection, and so on. It even lazily copies the processes, sending just a few stack frames and copying the rest on-demand. This all strikes me as terrifying - what happens if something fails, when everything is so interconnected? I believe they assume that nothing will fail, which makes it a completely beast than Erlang. In comparison Erlang is very simple and predictable. You the programmer can keep track of where everything is happening, and explicitly move things around (e.g. rpc:call/4) where desirable. The isolation between nodes is a huge feature since you can actually understand what happens when one of them fails. Life is good, hurray for Erlang! I don't want to knock Kali, because it looks very groovy, but it's the opposite of what I want for Erlang's bread-and-butter distributed networking applications. P.S., an even more far-out and fun integrated distributed system than Kali is Alan Bawden's "Linear Graph Reduction" stuff. He compiles programs into a graph representation where all their inter-references are apparent and then tries to dynamically arrange them between nodes to minimize network communication. Very beautifully written thesis: Implementing Distributed Systems Using Linear Naming ftp://publications.ai.mit.edu/ai-publications/1500-1999/AITR-1627.ps (1MB) Cheers, Luke From cpressey@REDACTED Mon Sep 29 23:02:31 2003 From: cpressey@REDACTED (Chris Pressey) Date: Mon, 29 Sep 2003 14:02:31 -0700 Subject: Opaque types (was: dictionaries, was: new syntax - a provocation) In-Reply-To: <3F785F72.6030201@web.de> References: <200309282324.h8SNOo8H067755@atlas.otago.ac.nz> <20030928222617.3607254f.cpressey@catseye.mine.nu> <3F781A9B.60304@web.de> <20030929084733.28fed3d4.cpressey@catseye.mine.nu> <3F785F72.6030201@web.de> Message-ID: <20030929140231.74be21a5.cpressey@catseye.mine.nu> On Mon, 29 Sep 2003 18:36:02 +0200 Joachim Durchholz wrote: > Chris Pressey wrote: > > Joachim Durchholz wrote: > > > >> Personally, I think that opaque data types should also interact > >> with pattern matching, i.e. there should also be "deconstructors". > >> For example, the Dictionary type should have something like a [H|R] > >> "destructor" that gave me the first pair (H) and the rest of the > >> dictionary (R), so that I can pattern match as in [(Key, > >> Value)|R]->... > > > > Well - maybe, but I don't see how it really fits in with the opacity > > - if you're not supposed to know anything about the structure of > > some > > value, then you probably shouldn't be taking it apart yourself, > > even > > in an abstract way. > > The key is that the designer of the type defines in which ways it > should be taken apart. > > For example, a Customer data type could have different "views": > Customer_by_address (Name, Nr, Street, Town, ...) > Customer_by_standing (Name, Nr, ABC) > Customer_by_history (Name, Nr, Transaction_List) > The nice thing here would be that it would be possible to extend the > Customer data type without having to rewrite all the code that does > pattern matching on Customer data, as long as the new data didn't show > up in the new views. Well, it's a very intriguing idea, but I'm still a bit trepidacious. The thing is, currently if you have code like function(A=[H|T]) -> ... you know for certain that A *is* a list. Now if other data types can match [H|T], A could be, well, anything. That's maybe not a practical problem though, and I definately like the general idea. I'll try to give it some thought. > >> The complaints won't be about dict, they will be about misbehaving > >> AXP switches and similar stuff... > > > > > > My guess would be that there would be none... but perhaps I have an > > unwarranted amount of faith in the idea that the great majority of > > paid Erlang programmers aren't idiots. > > Not idiots. Just programmers who have to make everyday compromises > between quality and time-to-market. Granted it's not solely idiocy that can lead to idiotic code. It still seems like the *oddest* corner to cut, though. I could *maybe* see the following code written in an outright panic: case A of L when is_list(L) -> something; D={dict, _, _, _, _, _, _, _, _} -> something_else end. But that's fairly easy to find and fix, like: is_dict(D) -> case catch dict:to_list(D) of L when is_list(L) -> true; {'EXIT',{badarg,_}} -> false end. ... IsDictA = is_dict(A), case A of L when is_list(L) -> something; D when IsDictA -> something_else end. The other point I'd like to make about this is that if the stability of your system is this crucial, like, say, a running carrier-class switch, you should probably *not* be upgrading your language/platform version at *all*, except for critical bugfixes. If backwards-compatibility really *is* sacred, then all effort spent on toothless futureproofing (like in dict, lib, io's ~n, etc) is completely wasted, because there won't *be* any future changes to proof *against*. Such effort would be better put to use providing a strictly-bugfix branch of Erlang/OTP IMHO. > > At any rate, if something explicitly undefined, like the > > representation of dicts, can't change, then I'm afraid we'll have to > > completely give up Joe's ideal of throwing other stuff (like > > records) out of Erlang, once better things are added. It will > > simply never happen. More incentive to start fresh with a > > completely new language, probably. > > Well, language tuning has never been a particularly rewarding job... No rest for the wicked :) > Regards, > Jo -Chris From joachim.durchholz@REDACTED Mon Sep 29 23:25:54 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Mon, 29 Sep 2003 23:25:54 +0200 Subject: Opaque types In-Reply-To: <20030929140231.74be21a5.cpressey@catseye.mine.nu> References: <200309282324.h8SNOo8H067755@atlas.otago.ac.nz> <20030928222617.3607254f.cpressey@catseye.mine.nu> <3F781A9B.60304@web.de> <20030929084733.28fed3d4.cpressey@catseye.mine.nu> <3F785F72.6030201@web.de> <20030929140231.74be21a5.cpressey@catseye.m Message-ID: <3F78A362.2070606@web.de> Chris Pressey wrote: > Joachim Durchholz wrote: > >>Chris Pressey wrote: >> >>>Joachim Durchholz wrote: >>> >>>>Personally, I think that opaque data types should also interact >>>>with pattern matching, i.e. there should also be "deconstructors". >>>>For example, the Dictionary type should have something like a [H|R] >>>> "destructor" that gave me the first pair (H) and the rest of the >>>>dictionary (R), so that I can pattern match as in [(Key, >>>>Value)|R]->... >>> >>>Well - maybe, but I don't see how it really fits in with the opacity >>>- if you're not supposed to know anything about the structure of >>>some value, then you probably shouldn't be taking it apart yourself, even >>>in an abstract way. >> >>The key is that the designer of the type defines in which ways it >>should be taken apart. >> >>For example, a Customer data type could have different "views": >> Customer_by_address (Name, Nr, Street, Town, ...) >> Customer_by_standing (Name, Nr, ABC) >> Customer_by_history (Name, Nr, Transaction_List) >>The nice thing here would be that it would be possible to extend the >>Customer data type without having to rewrite all the code that does >>pattern matching on Customer data, as long as the new data didn't show >>up in the new views. > > Well, it's a very intriguing idea, but I'm still a bit trepidacious. > > The thing is, currently if you have code like > > function(A=[H|T]) -> ... > > you know for certain that A *is* a list. Now if other data types can > match [H|T], A could be, well, anything. > > That's maybe not a practical problem though, and I definately like the > general idea. I'll try to give it some thought. Not a problem in practice - syntactically, a view would be the same as (or similar to) a function, and one can and must use the same rules. In other words: if [.|.] is a list "view", you can't use it for something else; you'd probably use some other name for deconstructing a dictionary (yes, the example chosen above was unfortunate). [snip discussion on more-or-less idiotic backwards compatibility issues - I'm sitting quite comfortably on both sides of the fence in this issue...] Regards, Jo From joachim.durchholz@REDACTED Mon Sep 29 23:32:41 2003 From: joachim.durchholz@REDACTED (Joachim Durchholz) Date: Mon, 29 Sep 2003 23:32:41 +0200 Subject: new syntax - a provocation In-Reply-To: References: <200309260019.h8Q0JCtF280244@atlas.otago.ac.nz> Message-ID: <3F78A4F9.6090203@web.de> Luke Gorrie wrote: >>It's interesting to consider the question: "what would an Erlang >>implementation have to be like for us to be able to take a running >>process and move it to another processor?" (IBM's AIX was able to >>do this on their mainframes, I believe. I think Kali Scheme can do it. > > And also the question: why would you want to? Seriously. Code upgrading for a set of communicating nodes, for example. (I haven't done this yet in Erlang, so the current methods may be enough. OTOH I suspect that such an upgrade could make good use of some automation, and that the Kali ideas are a step in the right direction.) > Kali Scheme looks extremely complex and subtle to me. In Kali you can > capture a process and send it to another machine, and it will > magically transport the related code on-demand, do distributed garbage > collection, and so on. Transporting the related code is trivial (in the sense that you need no rocket science to do that). Just patch up all calls to not-yet-transported functions with a stub that loads the code from the original location, for example - that's the lazy variant. Eagerly transporting the code is even simpler. > It even lazily copies the processes, sending > just a few stack frames and copying the rest on-demand. This all > strikes me as terrifying - what happens if something fails, when > everything is so interconnected? I believe they assume that nothing > will fail, which makes it a completely beast than Erlang. You can do this all both lazily or eagerly. Both would have their place even in Erlang - as a very fast-and-loose application, I'd copy everything within an application eagerly and the connections between applications lazily (because failure is an option there). Anyway, I think Richard was more interested in code migration than in lazy copying :-) Regards, Jo From ok@REDACTED Tue Sep 30 03:51:18 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Tue, 30 Sep 2003 13:51:18 +1200 (NZST) Subject: length() in guards Message-ID: <200309300151.h8U1pIsV501419@atlas.otago.ac.nz> I commented that (1) while computing length(X) is O(length(X)), which is not a nice thing to do in a guard, *comparing* length(X) N where N is a number can be done in O(min(length(X),N)) time, which is not so bad at all. (2) an examination of a large amount of existing Erlang code showed that most uses were of the safe/fast kind and that other uses could be avoided and in avoiding them you would get faster & clearer code anyway. Bengt Kleberg suggests: what about: is_length_equal( Var, Length ) is_length_greater( Var, Length ) is_length_less( Var, Length ) this would make it easier to remember, imho. Well, no. First, the direct connection between length/1 and what's happening is severed. Second, instead of remembering one function and 8 relational operators, I would now have to remember one function and 16 relational operators, which is not good. Third, the spelling of "is_length_greater" is arbitrary; my Scheme code uses "length>?" which conforms to existing Scheme naming conventions, so doesn't require any special effort of memory. Fourth, and most important, it's not actually a compatible change. Fifth, there is a substantial documentation cost for adding these guards. Here's what I had in mind. Step 1: Implement if_length_ instructions in BEAM. Step 2: Make the compiler recognise length(X) E and E length(X) as special cases, and generate the new instructions. Step 3: Make the compiler *warn* if there is a use of length/1 in a guard that isn't caught by step 2, *but* continue to generate the same code as is now generated. Step 4: Encouraged by the warning, people clean up their code. Step 5: You were expecting me to say "turn the warning into an error", maybe? No, there is no step 5. The point is that _existing_ code can benefit from this observation _without any change at all_. Code which is unclear/inefficient is pointed out when you get to step 3, but is never broken. From ok@REDACTED Tue Sep 30 05:53:28 2003 From: ok@REDACTED (Richard A. O'Keefe) Date: Tue, 30 Sep 2003 15:53:28 +1200 (NZST) Subject: length() in guards Message-ID: <200309300353.h8U3rSur087074@atlas.otago.ac.nz> Raimo Niskanen wrote: We have already thought of a possible optimization in the compiler to convert such as "length(L) > 3" to an internal "length_gt(L, 3)", but it was not possible without changing the semantics of length(L). Oh *curse*, that's right. Worse still, on examining the latest sources, I see that there _are_ cases when length/1 is used to test whether something is a proper list or not. What a nuisance. The observation remains: - *most* of the uses of length/1 in guards could use a bounded-time test because they are known to be given lists; - *most* of the rest could be rewritten with an improvement in both speed and clarity. A set of length_{lt,eq,gt,ge,ne,le}/2 guard tests, however spelled, would be useful. From fredrik.linder@REDACTED Tue Sep 30 13:35:37 2003 From: fredrik.linder@REDACTED (Fredrik Linder) Date: Tue, 30 Sep 2003 13:35:37 +0200 Subject: length() in guards In-Reply-To: <200309300353.h8U3rSur087074@atlas.otago.ac.nz> Message-ID: The observation made by O'Keefe is imho a good one. is_length(L, 3) % same as is_length(L, '==', 3) is_length(L, '=<', 3) % does not check value of tl(tl(tl(L))) (Did I get then number of calls to tl/1 right? (:-) /Fredrik > -----Original Message----- > From: owner-erlang-questions@REDACTED > [mailto:owner-erlang-questions@REDACTED]On Behalf Of Richard A. > O'Keefe > Sent: den 30 september 2003 05:53 > To: erlang-questions@REDACTED > Subject: Re: length() in guards > > > Raimo Niskanen wrote: > We have already thought of a possible optimization in the > compiler to convert such as "length(L) > 3" to an internal > "length_gt(L, 3)", but it was not possible without changing the > semantics of length(L). > > Oh *curse*, that's right. Worse still, on examining the latest sources, > I see that there _are_ cases when length/1 is used to test > whether something > is a proper list or not. What a nuisance. > > The observation remains: > - *most* of the uses of length/1 in guards could use a bounded-time > test because they are known to be given lists; > - *most* of the rest could be rewritten with an improvement in both > speed and clarity. > > A set of length_{lt,eq,gt,ge,ne,le}/2 guard tests, however spelled, > would be useful. > > From luke@REDACTED Tue Sep 30 15:45:44 2003 From: luke@REDACTED (Luke Gorrie) Date: 30 Sep 2003 15:45:44 +0200 Subject: new syntax - a provocation In-Reply-To: <3F78A4F9.6090203@web.de> References: <200309260019.h8Q0JCtF280244@atlas.otago.ac.nz> <3F78A4F9.6090203@web.de> Message-ID: Joachim Durchholz writes: > Luke Gorrie wrote: > > >>It's interesting to consider the question: "what would an Erlang > >>implementation have to be like for us to be able to take a running > >>process and move it to another processor?" (IBM's AIX was able to > >>do this on their mainframes, I believe. I think Kali Scheme can do it. > > > > And also the question: why would you want to? Seriously. > > Code upgrading for a set of communicating nodes, for example. But why would that involve moving a _process_ from one node to another? > (I haven't done this yet in Erlang, so the current methods may be > enough. OTOH I suspect that such an upgrade could make good use of > some automation, and that the Kali ideas are a step in the right > direction.) In Erlang the most basic way to load a new module definition on all nodes is something like: (b@REDACTED)3> F = "/home/luke/devel/erlang/foo.beam". "/home/luke/devel/erlang/foo.beam" (b@REDACTED)4> {ok, Code} = file:read_file(F). {ok,<<70,79,82,49,0,0,14,...>>} (b@REDACTED)5> rpc:multicall([node()|nodes()], code, load_binary, [foo,F,Code]). {[{module,foo},{module,foo}],[]} That loads foo.beam on every node, including the current one. As I understand it, the OTP release/upgrade management system is a scripting language that interleaves loading of new modules, notifying servers that their code has changed (or restarting them), and so on. In Erlang usage today I think most of us assume that all connected nodes will be running the same code. > You can do this all both lazily or eagerly. Both would have their > place even in Erlang - as a very fast-and-loose application, I'd copy > everything within an application eagerly and the connections between > applications lazily (because failure is an option there). > > Anyway, I think Richard was more interested in code migration than in > lazy copying :-) Interesting. My interpretation was entirely different: taking a process - its continuation, its private heap, its identity (pid) - and moving it to another node. Some sort of magic move_process(Pid,Node) BIF. I assume that all nodes are running the same code -- or at least that handling code consistency/loading issues is a separate problem. The tricky part seems to be moving the identity. Is there a simple way to do this that would be generally useful? If not, I'm more inclined to just write some code to kill the process on one node and start the new one on the other by hand. I'm racking my brain for examples in our system where we more-or-less move a process from one node to another. The closest I can think of is with servers that are global to the cluster - if their node goes down the process should be restarted on another, which is a bit like moving it. Trouble is, you can't really move a process after its machine has crashed or been isolated from the network :-). We use the 'global' module to manage these 'one-per-cluster' server processes. Cheers, Luke From bernardp@REDACTED Tue Sep 30 18:39:14 2003 From: bernardp@REDACTED (Pierpaolo BERNARDI) Date: Tue, 30 Sep 2003 18:39:14 +0200 Subject: new syntax - a provocation References: <200309260019.h8Q0JCtF280244@atlas.otago.ac.nz> <3F78A4F9.6090203@web.de> Message-ID: <004801c38771$62939840$5ff36850@c1p4e3> > Joachim Durchholz writes: > > > Luke Gorrie wrote: > > > > >>It's interesting to consider the question: "what would an Erlang > > >>implementation have to be like for us to be able to take a running > > >>process and move it to another processor?" (IBM's AIX was able to > > >>do this on their mainframes, I believe. I think Kali Scheme can do it. > > > > > > And also the question: why would you want to? Seriously. Because the node on which the process is running must be shut down for maintenance, upgraded, moved, load balanced, repainted, cloned ... The logic for doing this can be embedded ad hoc in each process, or it can be designed once and for all in the VM. I think that's where IBM and Kali are/where directed to. Cheers P. From vances@REDACTED Tue Sep 30 21:03:12 2003 From: vances@REDACTED (Vance Shipley) Date: Tue, 30 Sep 2003 15:03:12 -0400 Subject: One Million Processes Message-ID: <20030930190312.GR70644@frogman.motivity.ca> I would like to put together an application for the sole purpose of achieving one million processes doing something productive. With current limits on the number of processes which a node can support this will require several nodes. I am building a platform to host a number of Sun CP1500 Sparc boards in a single chassis. I'll have at least a half a dozen available. These will all be independent, diskless clients. I would like to also keep the distributed system it comprises up and running continuosly. Forever. I'm soliciting suggestions on an application to create. The goal is to demonstrate massive concurrency. One thing I played around with this year was implementing the digraph module with every vertice as a process. It becomes a living database. Another obvious choice is the game of life. I'd prefer something a little more impressive though. If anyone has any other interesting things they could do with an Erlang/OTP cluster I can make it available. -Vance From vlad_dumitrescu@REDACTED Tue Sep 30 21:21:02 2003 From: vlad_dumitrescu@REDACTED (Vlad Dumitrescu) Date: Tue, 30 Sep 2003 21:21:02 +0200 Subject: new syntax - a provocation References: <200309260019.h8Q0JCtF280244@atlas.otago.ac.nz> <3F78A4F9.6090203@web.de> Message-ID: <> It is interesting how languages and environments are modelled after their intended use (form follows function here too) A similar thing, but reversed, can be said about another feature relative to code migration: security. Erlang assumes all participants are fully trusted when they are accepted as peers, and all code is friendly, which has shown to be restricting when one wants to open up across the Internet. Of course, work is being done to try to make it work, but I suspect others are also trying to cope with failure too. /Vlad From luke@REDACTED Tue Sep 30 21:47:05 2003 From: luke@REDACTED (Luke Gorrie) Date: 30 Sep 2003 21:47:05 +0200 Subject: new syntax - a provocation In-Reply-To: <004801c38771$62939840$5ff36850@c1p4e3> References: <200309260019.h8Q0JCtF280244@atlas.otago.ac.nz> <3F78A4F9.6090203@web.de> <004801c38771$62939840$5ff36850@c1p4e3> Message-ID: "Pierpaolo BERNARDI" writes: > > > > And also the question: why would you want to? Seriously. > > Because the node on which the process is running must be shut > down for maintenance, upgraded, moved, load balanced, > repainted, cloned ... To smoothly fail over a whole node you would need to include a lot of operating system state: sockets, open files, and so on. Perhaps this is what AIX does when moving processes around in mainframes. Another approach would be not depend on any such non-movable state - e.g. if you are doing a 'pure' parallel computation. Perhaps this is Kali's approach. If your Erlang nodes are Unix processes on separate machines with lots of open sockets and files - the typical case - then I don't think this sort of transparent fail-over is realistic. But if your application is fault-tolerant and will detect and recover from the sudden total failure of a node/machine, then you've got a pretty good base-line to handle these upgrade/move/new-paintjob situations methinks. Back to the original point, I don't think that having a shared atom heap within BEAM would be a serious obstacle in these situations :-) Cheers, Luke (Note: Repainting our appliances any colour but green will void your warranty!)