From ingela@REDACTED Fri Nov 2 15:12:50 2007 From: ingela@REDACTED (Ingela Anderton Andin) Date: Fri, 02 Nov 2007 15:12:50 +0100 Subject: [erlang-bugs] ODBC enhancement: support for out & inout parameters for stored procedures In-Reply-To: <200710292236.l9TMaGBI071136@snookles.snookles.com> References: <200710292236.l9TMaGBI071136@snookles.snookles.com> Message-ID: <472B3062.70006@erix.ericsson.se> Hi! We can absolutely add this patch to odbc if it will pass our test-suite. However it will probably not make it in time for R12B but maybe R12B-1. It would also be good to have some new test case for this functionality. If you could provide some test data it would speed things up. Preferably the test should be able to run on all database backends. If it can not be made genericly we already use callbacks for some special cases. The currently tested backends are sql-server and postgres. The test case should create a data base table, do operations on the table to verify the functionality and then drop the table. Regards Ingela - OTP team Scott Lystig Fritchie wrote: > Howdy. We've been using the patch below for months without any ill > effect and are wondering if it'd be useful for the community at > large. IIRC, it supports out & inout parameters for stored > procedures ... er, or something else that the ODBC driver can't quite > do. :-) > > -Scott > > --- snip --- snip --- snip --- snip --- snip --- snip --- > > --- ./otp_src_R11B-5/lib/odbc/c_src/odbcserver.c.org 2007-01-29 05:17:56.000000000 -0800 > +++ ./otp_src_R11B-5/lib/odbc/c_src/odbcserver.c 2007-07-24 19:03:43.000000000 -0700 > @@ -81,7 +81,8 @@ > N - integer > Binary - binary encodede tuple of {SQLQuery, NoRows, Parameters} > NoRows - integer > - Parameters - [{Datatype, Value}] > + Parameters - [{Datatype, InOrOut, Value}] > + InOrOut = [IN | OUT | INOUT] > Datatype - USER_INT | USER_SMALL_INT | {USER_DECIMAL, Precision, Scale} | > {USER_NMERIC, Precision, Scale} | {USER_CHAR, Max} | {USER_VARCHAR, Max} | > {USER_FLOAT, Precision} | USER_REAL | USER_DOUBLE > @@ -144,6 +145,10 @@ > static db_result_msg encode_result(db_state *state); > static db_result_msg encode_result_set(SQLSMALLINT num_of_columns, > db_state *state); > +static db_result_msg encode_out_params(db_state *state, > + int cols, > + param_array *params, > + int num_param_values); > static db_result_msg encode_column_name_list(SQLSMALLINT num_of_columns, > db_state *state); > static db_result_msg encode_value_list(SQLSMALLINT num_of_columns, > @@ -203,7 +208,7 @@ > static void init_driver(int erl_auto_commit_mode, int erl_trace_driver, > db_state *state); > static void init_param_column(param_array *params, byte *buffer, int *index, > - int num_param_values); > + int num_param_values, db_state* state); > > static void init_param_statement(int cols, > int num_param_values, > @@ -225,6 +230,7 @@ > db_state *state); > static db_result_msg retrive_scrollable_cursor_support_info(db_state > *state); > +static int num_out_params(int num_of_params, param_array* params); > /* ------------- Error handling functions --------------------------------*/ > > static diagnos get_diagnos(SQLSMALLINT handleType, SQLHANDLE handle); > @@ -240,7 +246,7 @@ > # define DO_EXIT(code) do { ExitProcess((code)); exit((code));} while (0) > /* exit() called only to avoid a warning */ > #else > -# define DO_EXIT(code) exit((code)) > +# define DO_EXIT(code) _exit((code)) > #endif > > /* ----------------- Main functions --------------------------------------*/ > @@ -327,7 +333,7 @@ > byte *request_buffer = NULL; > db_state state = > {NULL, NULL, NULL, NULL, 0, {NULL, 0, 0}, > - FALSE, FALSE, FALSE, FALSE, FALSE}; > + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}; > byte request_id; > #ifdef WIN32 > SOCKET socket; > @@ -771,7 +777,11 @@ > } > if(msg.length == 0) { > ei_x_new_with_version(&dynamic_buffer(state)); > - msg = encode_result(state); > + if(out_params(state)){ > + msg = encode_out_params(state, cols, params, num_param_values); > + }else{ > + msg = encode_result(state); > + } > if(msg.length == 0) { > msg.buffer = dynamic_buffer(state).buff; > msg.length = dynamic_buffer(state).index; > @@ -951,9 +961,9 @@ > } > > if (num_of_columns == 0) { > - elements = 2; > - atom = "updated"; > - update = TRUE; > + elements = 2; > + atom = "updated"; > + update = TRUE; > } else { > elements = 3; > atom = "selected"; > @@ -1011,6 +1021,85 @@ > return msg; > } > > +static db_result_msg encode_out_params(db_state *state, > + int num_of_params, > + param_array* params, > + int num_param_values) > +{ > + int num_of_columns = 0; > + int i = 0; > + int j = 0; > + param_array column; > + db_result_msg msg; > + msg = encode_empty_message(); > + > + ei_x_encode_tuple_header(&dynamic_buffer(state), 3); > + ei_x_encode_atom(&dynamic_buffer(state), "executed"); > + > + num_of_columns = num_out_params(num_of_params, params); > + ei_x_encode_long(&dynamic_buffer(state), num_of_columns); > + > + ei_x_encode_list_header(&dynamic_buffer(state), num_param_values); > + for(j =0; j < num_param_values; j ++){ > + > + if(tuple_row(state)) { > + ei_x_encode_tuple_header(&dynamic_buffer(state), num_of_columns); > + > + } else { > + ei_x_encode_list_header(&dynamic_buffer(state), num_of_columns); > + } > + > + for (i = 0; i< num_of_params; i++) { > + if(params[i].input_output_type==SQL_PARAM_INPUT){ > + continue; > + } > + column = params[i]; > + if (column.type.len == 0 || > + column.type.strlen_or_indptr == SQL_NULL_DATA) { > + ei_x_encode_atom(&dynamic_buffer(state), "null"); > + } else { > + void* values = retrive_param_values(&column); > + switch(column.type.c) { > + case SQL_C_CHAR: > + ei_x_encode_string(&dynamic_buffer(state), ((char*)values)+j*column.type.len); > + break; > + case SQL_C_SLONG: > + ei_x_encode_long(&dynamic_buffer(state), ((long*)values)[j]); > + break; > + case SQL_C_DOUBLE: > + ei_x_encode_double(&dynamic_buffer(state), > + ((double*)values)[j]); > + break; > + case SQL_C_BIT: > + ei_x_encode_atom(&dynamic_buffer(state), > + ((Boolean*)values)[j]==TRUE?"true":"false"); > + break; > + default: > + ei_x_encode_atom(&dynamic_buffer(state), "error"); > + break; > + } > + } > + } > + if(!tuple_row(state)) { > + ei_x_encode_empty_list(&dynamic_buffer(state)); > + } > + } > + ei_x_encode_empty_list(&dynamic_buffer(state)); > + return msg; > +} > + > +static int num_out_params(int num_of_params, param_array* params) > +{ > + int ret = 0; > + int i = 0; > + for(i=0; i < num_of_params; i++){ > + if(params[i].input_output_type==SQL_PARAM_INPUT_OUTPUT || > + params[i].input_output_type==SQL_PARAM_OUTPUT) > + ret++; > + } > + return ret; > +} > + > /* Description: Encodes the result set into the "ei_x" - dynamic_buffer > held by the state variable */ > static db_result_msg encode_result_set(SQLSMALLINT num_of_columns, > @@ -1514,7 +1603,9 @@ > } > > /* ------------- Socket communication functions --------------------------*/ > -#ifdef WIN32 > +#define USE_IPV4 > +#define SOCKET int > +#if defined WIN32 || defined USE_IPV4 > /* Currently only an old windows compiler is supported so we do not have ipv6 > capabilities */ > static SOCKET connect_to_erlang(const char *port) > @@ -1856,10 +1947,11 @@ > } > > static void init_param_column(param_array *params, byte *buffer, int *index, > - int num_param_values) > + int num_param_values, db_state* state) > { > int size, erl_type; > long user_type, precision, scale, length, dummy; > + long in_or_out; > > ei_decode_long(buffer, index, &user_type); > > @@ -1972,6 +2064,20 @@ > break; > } > params->offset = 0; > + > + ei_decode_long(buffer, index, &in_or_out); > + switch((in_or_out_type)in_or_out){ > + case(OUT): > + out_params(state) = TRUE; > + params->input_output_type = SQL_PARAM_OUTPUT; break; > + case(INOUT): > + out_params(state) = TRUE; > + params->input_output_type = SQL_PARAM_INPUT_OUTPUT; break; > + case(IN): > + default: > + params->input_output_type = SQL_PARAM_INPUT; break; > + } > + > } > > static void init_param_statement(int cols, int num_param_values, > @@ -1987,7 +2093,8 @@ > DO_EXIT(EXIT_ALLOC); > } > > - > + if(num_param_values <= 1) return; > + > if(!sql_success(SQLSetStmtAttr(statement_handle(state), > SQL_ATTR_PARAM_BIND_TYPE, > SQL_PARAM_BIND_BY_COLUMN, 0))) { > @@ -2129,7 +2236,7 @@ > > ei_decode_tuple_header(buffer, index, &size); > > - init_param_column(¶ms[i], buffer, index, num_param_values); > + init_param_column(¶ms[i], buffer, index, num_param_values, state); > > ei_decode_list_header(buffer, index, &size); > > @@ -2153,7 +2260,7 @@ > > if(!sql_success( > SQLBindParameter(statement_handle(state), i + 1, > - SQL_PARAM_INPUT, > + params[i].input_output_type, > params[i].type.c, > params[i].type.sql, > params[i].type.col_size, > --- ./otp_src_R11B-5/lib/odbc/c_src/odbcserver.h.org 2007-01-29 05:18:02.000000000 -0800 > +++ ./otp_src_R11B-5/lib/odbc/c_src/odbcserver.h 2007-07-24 19:01:23.000000000 -0700 > @@ -142,6 +142,7 @@ > typedef struct { > col_type type; > int offset; > + SQLUSMALLINT input_output_type; > union { > byte *string; > long *integer; > @@ -167,8 +168,15 @@ > Boolean tuple_row; > Boolean exists_more_result_sets; > Boolean param_query; > + Boolean out_params; > } db_state; > > +typedef enum { > + IN = 0, > + OUT=1, > + INOUT=2 > +} in_or_out_type; > + > #define connection_handle(db_state) (db_state -> connection_handle) > #define environment_handle(db_state) (db_state -> environment_handle) > #define statement_handle(db_state) (db_state -> statement_handle) > @@ -180,3 +188,4 @@ > #define tuple_row(db_state) (db_state -> tuple_row) > #define exists_more_result_sets(db_state) (db_state -> exists_more_result_sets) > #define param_query(db_state) (db_state -> param_query) > +#define out_params(db_state) (db_state -> out_params) > --- ./otp_src_R11B-5/lib/odbc/src/odbc.erl.org 2007-01-29 05:17:55.000000000 -0800 > +++ ./otp_src_R11B-5/lib/odbc/src/odbc.erl 2007-07-24 19:01:23.000000000 -0700 > @@ -864,23 +864,31 @@ > end. > > %%------------------------------------------------------------------------- > -fix_params({sql_integer, Values}) -> > - {?USER_INT, [256 | Values]}; > -fix_params({sql_smallint, Values}) -> > - {?USER_SMALL_INT, [256 | Values]}; > -fix_params({sql_tinyint, Values}) -> > - {?USER_TINY_INT, [256 | Values]}; > -fix_params({{sql_decimal, Precision, 0}, > +%% integer values(0, 1, 2) are defined in odbcserver.h - in_or_out_type > +fix_inout(in) -> > + 0; > +fix_inout(out) -> > + 1; > +fix_inout(inout) -> > + 2. > + > +fix_params({sql_integer, InOut, Values}) -> > + {?USER_INT, fix_inout(InOut), [256 | Values]}; > +fix_params({sql_smallint, InOut, Values}) -> > + {?USER_SMALL_INT, fix_inout(InOut), [256 | Values]}; > +fix_params({sql_tinyint, InOut, Values}) -> > + {?USER_TINY_INT, fix_inout(InOut), [256 | Values]}; > +fix_params({{sql_decimal, InOut, Precision, 0}, > Values}) when Precision >= 0, Precision =< 9 -> > - {?USER_DECIMAL, Precision, 0, [256 | Values]}; > -fix_params({{sql_decimal, Precision, Scale}, Values}) -> > - {?USER_DECIMAL, Precision, Scale, Values}; > -fix_params({{sql_numeric, Precision, 0}, > + {?USER_DECIMAL, Precision, 0, fix_inout(InOut), [256 | Values]}; > +fix_params({{sql_decimal, InOut, Precision, Scale}, Values}) -> > + {?USER_DECIMAL, Precision, Scale, fix_inout(InOut), Values}; > +fix_params({{sql_numeric, InOut, Precision, 0}, > Values}) when Precision >= 0, Precision =< 9 -> > - {?USER_NUMERIC, Precision, 0, [256 | Values]}; > -fix_params({{sql_numeric, Precision, Scale}, Values}) -> > - {?USER_NUMERIC, Precision, Scale, Values}; > -fix_params({{sql_char, Max}, Values}) -> > + {?USER_NUMERIC, Precision, 0, fix_inout(InOut), [256 | Values]}; > +fix_params({{sql_numeric, InOut, Precision, Scale}, Values}) -> > + {?USER_NUMERIC, Precision, Scale, fix_inout(InOut), Values}; > +fix_params({{sql_char, InOut, Max}, Values}) -> > NewValues = > case (catch > lists:map(fun(Str) -> Str ++ [?STR_TERMINATOR] end, Values)) of > @@ -889,8 +897,8 @@ > Result -> > Result > end, > - {?USER_CHAR, Max, NewValues}; > -fix_params({{sql_varchar, Max}, Values}) -> > + {?USER_CHAR, Max, fix_inout(InOut), NewValues}; > +fix_params({{sql_varchar, InOut, Max}, Values}) -> > NewValues = > case (catch > lists:map(fun(Str) -> Str ++ [?STR_TERMINATOR] end, Values)) of > @@ -899,12 +907,36 @@ > Result -> > Result > end, > - {?USER_VARCHAR, Max, NewValues}; > + {?USER_VARCHAR, Max, fix_inout(InOut), NewValues}; > +fix_params({{sql_float, InOut, Precision}, Values}) -> > + {?USER_FLOAT, Precision, fix_inout(InOut), Values}; > +fix_params({sql_real, InOut, Values}) -> > + {?USER_REAL, fix_inout(InOut), Values}; > +fix_params({sql_double, InOut, Values}) -> > + {?USER_DOUBLE, fix_inout(InOut), Values}; > +fix_params({sql_bit, InOut, Values}) -> > + {?USER_BOOLEAN, fix_inout(InOut), Values}; > +%% default is IN %%% > +fix_params({sql_integer, Values}) -> > + fix_params({sql_integer, in, Values}); > +fix_params({sql_smallint, Values}) -> > + fix_params({sql_smallint, in, Values}); > +fix_params({sql_tinyint, Values}) -> > + fix_params({sql_tinyint, in, Values}); > +fix_params({{sql_decimal, Precision, Scale}, Values}) -> > + fix_params({{sql_decimal, in, Precision, Scale}, Values}); > +fix_params({{sql_numeric, Precision, Scale}, Values}) -> > + fix_params({{sql_numeric, in, Precision, Scale}, Values}); > +fix_params({{sql_char, Max}, Values}) -> > + fix_params({{sql_char, in, Max}, Values}); > +fix_params({{sql_varchar, Max}, Values}) -> > + fix_params({{sql_varchar, in, Max}, Values}); > fix_params({{sql_float, Precision}, Values}) -> > - {?USER_FLOAT, Precision, Values}; > + fix_params({{sql_float, in, Precision}, Values}); > fix_params({sql_real, Values}) -> > - {?USER_REAL, Values}; > + fix_params({sql_real, in, Values}); > fix_params({sql_double, Values}) -> > - {?USER_DOUBLE, Values}; > + fix_params({sql_double, in, Values}); > fix_params({sql_bit, Values}) -> > - {?USER_BOOLEAN, Values}. > + fix_params({sql_bit, in, Values}). > + > _______________________________________________ > erlang-bugs mailing list > erlang-bugs@REDACTED > http://www.erlang.org/mailman/listinfo/erlang-bugs > > From john.hughes@REDACTED Tue Nov 6 19:36:09 2007 From: john.hughes@REDACTED (John Hughes) Date: Tue, 6 Nov 2007 19:36:09 +0100 Subject: [erlang-bugs] Loss of sharing Message-ID: <004301c820a3$e78091a0$b681b4e0$@hughes@quviq.com> Try running hog:main() in the program below. It creates a data structure in one process, measuring heap size, and how it changes during the creation. Then it sends it to another, measuring the memory allocated in the receiving process. Here's the output: Creating tree:: allocated 0 bytes, heap size 987 bytes Receiving tree:: allocated 116769407 bytes, heap size 116769640 bytes true That is, the structure is less than 1K bytes in the sender, but over 100MB in the receiver. The reason is that it contains a lot of sharing, and sharing is lost when messages are sent to other processes. Sharing is ALSO lost when values are copied to a new process being spawned. In fact, I've found no way to copy structures between processes WITHOUT losing sharing. This means that some data simply cannot practically be sent from one process to another. I understand, of course, that if I send the same structure IN TWO SEPARATE MESSAGES, that I am bound to get two copies in the receiver. But if I send a structure in ONE message, then there's in principle no reason why the copy could not preserve sharing. That's true even when copying between nodes. In my real application the data is funs, constructed in a complex manner so that I cannot predict the sharing. When the sharing is lost, they get bigger than the tree in my example. If I can't preserve sharing when I send them to another process, then I can't structure my program using processes. That, in turn, limits my ability to trap exits. Any chance of introducing a sharing-preserving copy in message send and spawn? It would be really useful! John Hughes -module(hog). -compile(export_all). % Builds a binary tree of depth N. Note the sharing! tree(0) -> leaf; tree(N) -> T = tree(N-1), {T,T}. measure(S,F) -> {heap_size,Before} = process_info(self(),heap_size), Result = F(), {heap_size,After} = process_info(self(),heap_size), io:format("~s: allocated ~w bytes, heap size ~w bytes~n", [S,After-Before,After]), Result. main() -> T = measure("Creating tree:",fun() -> tree(25) end), Child = spawn(fun() -> child() end), erlang:yield(), Child ! T, erlang:yield(). child() -> measure("Receiving tree:",fun() -> receive Tree -> ok end end). -------------- next part -------------- An HTML attachment was scrubbed... URL: From bjorn@REDACTED Wed Nov 7 06:35:01 2007 From: bjorn@REDACTED (Bjorn Gustavsson) Date: 07 Nov 2007 06:35:01 +0100 Subject: [erlang-bugs] Loss of sharing In-Reply-To: <004301c820a3$e78091a0$b681b4e0$@hughes@quviq.com> References: <004301c820a3$e78091a0$b681b4e0$@hughes@quviq.com> Message-ID: "John Hughes" writes: > Try running hog:main() in the program below. It creates a data structure in > one process, measuring heap size, and how it changes during the creation. > Then it sends it to another, measuring the memory allocated in the receiving > process. Here's the output: > > Creating tree:: allocated 0 bytes, heap size 987 bytes > > Receiving tree:: allocated 116769407 bytes, heap size 116769640 bytes > > true > > That is, the structure is less than 1K bytes in the sender, but over 100MB > in the receiver. > For the traditional type of applications that Erlang is typically is used for, loss of sharing is not an issue. There is typically no sharing at all. Therefore term copying between process is optimized for speed. > > The reason is that it contains a lot of sharing, and sharing is lost when > messages are sent to other processes. Sharing is ALSO lost when values are > copied to a new process being spawned. In fact, I've found no way to copy > structures between processes WITHOUT losing sharing. This means that some > data simply cannot practically be sent from one process to another. Correct. > > Any chance of introducing a sharing-preserving copy in message send and > spawn? It would be really useful! It is not likely that it will become the default behaviour. But it could be possible to make it possible as an option, for instance a new option for the erlang:send/3 BIF. /Bjorn -- Bj?rn Gustavsson, Erlang/OTP, Ericsson AB From xpdoka@REDACTED Fri Nov 9 17:33:48 2007 From: xpdoka@REDACTED (Dominic Williams) Date: Fri, 9 Nov 2007 17:33:48 +0100 (CET) Subject: [erlang-bugs] Does 'ic' (the CORBA IDL compiler) support recursive types? In-Reply-To: References: Message-ID: <7732.217.128.75.198.1194626028.squirrel@www.geekisp.com> Hi Nick, > After a quick search in my mail boxes I found that the last time someone > asked about rescursive types was back in Nov 2003. As you understand, > since it's seldom used and one can solve this in other ways, it hasn't > been a high prio IC extension. I would just like to point out that this rationale only applies to projects using Erlang and Orber for custom CORBA interfaces (when the IDL can be modified at will to work around an IC limitation). We use Erlang and Orber in a product which allows our customers to interface with any CORBA server themselves, without coding anything. In practice they use this to interface with legacy external systems with a fixed, published IDL that cannot be changed. Luckily we have not yet come across one such IDL using recursive types, but it would be preferable, for projects such as ours integrating Orber and IC as a component of our product rather than using it as an internal development tool, if IC could handle any legal IDL. Regards, Dominic Williams http://dominicwilliams.net ---- From john.hughes@REDACTED Sat Nov 10 12:18:56 2007 From: john.hughes@REDACTED (John Hughes) Date: Sat, 10 Nov 2007 12:18:56 +0100 Subject: [erlang-bugs] Lists module funnies In-Reply-To: References: Message-ID: <047501c8238b$7c7de1b0$7579a510$@hughes@quviq.com> What's the next element in this sequence? 1> lists:seq(1,3). [1,2,3] 2> lists:seq(1,2). [1,2] 3> lists:seq(1,1). [1] 4> lists:seq(1,0). I expect [], but what I get is: =ERROR REPORT==== 10-Nov-2007::12:11:21 === Error in process <0.30.0> with exit value: {function_clause,[{lists,seq,[1,0]},{ erl_eval,do_apply,5},{shell,exprs,6},{shell,eval_loop,3}]} ** exited: {function_clause,[{lists,seq,[1,0]}, {erl_eval,do_apply,5}, {shell,exprs,6}, {shell,eval_loop,3}]} ** I've worked around this more times than I can remember, special-casing the zero case to avoid calling seq, and I'll bet that many callers of seq have to do the same thing. Any chance of changing this in the future? There can't be much code that would break... code that only works today *because* seq raises an exception. John Hughes From exta7@REDACTED Sun Nov 11 11:53:40 2007 From: exta7@REDACTED (Zvi) Date: Sun, 11 Nov 2007 02:53:40 -0800 (PST) Subject: [erlang-bugs] Lists module funnies In-Reply-To: <047501c8238b$7c7de1b0$7579a510$@hughes@quviq.com> References: <047501c8238b$7c7de1b0$7579a510$@hughes@quviq.com> Message-ID: <13690246.post@talk.nabble.com> This is what I get in Matlab: >> 1:0 ans = Empty matrix: 1-by-0 Anyway, I missing some Matlab-like syntactic sugar, this will be especially usefull in list comprehensions: >> 1:10 ans = 1 2 3 4 5 6 7 8 9 10 >> 10:-1:1 ans = 10 9 8 7 6 5 4 3 2 1 >> 0:0.1:1 ans = 0 0.1000 0.2000 0.3000 0.4000 0.5000 0.6000 0.7000 0.8000 0.9000 1.0000 Since ":" has special meaning in Erlang, as separator between module and function names, we can use "..", this is similar to range in Pascal/Ada. This might be implented as operator erlang:'..'/2 or erlang:'..'/3 From..To == lists:seq(From,To) or From..Step..To == lists:seq(From,To,Step) except, that lists:seq doesn't support floats. Then calculating Multiplication table will look like this: Table = [{N,M,N*M} || N<-1..10, M<-1..10]. Can this be implemented in R12 ? Thanks in advance Zvi John Hughes-7 wrote: > > What's the next element in this sequence? > > 1> lists:seq(1,3). > [1,2,3] > 2> lists:seq(1,2). > [1,2] > 3> lists:seq(1,1). > [1] > 4> lists:seq(1,0). > > I expect [], but what I get is: > > =ERROR REPORT==== 10-Nov-2007::12:11:21 === > Error in process <0.30.0> with exit value: > {function_clause,[{lists,seq,[1,0]},{ > erl_eval,do_apply,5},{shell,exprs,6},{shell,eval_loop,3}]} > > ** exited: {function_clause,[{lists,seq,[1,0]}, > {erl_eval,do_apply,5}, > {shell,exprs,6}, > {shell,eval_loop,3}]} ** > > I've worked around this more times than I can remember, special-casing the > zero case to avoid calling seq, and I'll bet that many callers of seq have > to do the same thing. Any chance of changing this in the future? There > can't > be much code that would break... code that only works today *because* seq > raises an exception. > > John Hughes > > _______________________________________________ > erlang-bugs mailing list > erlang-bugs@REDACTED > http://www.erlang.org/mailman/listinfo/erlang-bugs > > -- View this message in context: http://www.nabble.com/Lists-module-funnies-tf4782240.html#a13690246 Sent from the Erlang Bugs mailing list archive at Nabble.com. From tobbe@REDACTED Mon Nov 12 09:54:03 2007 From: tobbe@REDACTED (Torbjorn Tornkvist) Date: Mon, 12 Nov 2007 09:54:03 +0100 Subject: [erlang-bugs] Lists module funnies In-Reply-To: <3598.70914039693$1194693693@news.gmane.org> References: <3598.70914039693$1194693693@news.gmane.org> Message-ID: While on the topic, wouldn't it be nice with arithmetic sequences a la Haskell? Example: [2,3..10] => [2,3,4,5,6,7,8,9,10] [2,1.8..1] => [2,1.8,1.6,1.4,1.2,1] The semantics is thus something like: [a,b..c] => d=b-a, [a,a+d,a+d*2,a+d*3,..etc...] until a+d*X > c Cheers, Tobbe John Hughes wrote: > What's the next element in this sequence? > > 1> lists:seq(1,3). > [1,2,3] > 2> lists:seq(1,2). > [1,2] > 3> lists:seq(1,1). > [1] > 4> lists:seq(1,0). > > I expect [], but what I get is: > > =ERROR REPORT==== 10-Nov-2007::12:11:21 === > Error in process <0.30.0> with exit value: > {function_clause,[{lists,seq,[1,0]},{ > erl_eval,do_apply,5},{shell,exprs,6},{shell,eval_loop,3}]} > > ** exited: {function_clause,[{lists,seq,[1,0]}, > {erl_eval,do_apply,5}, > {shell,exprs,6}, > {shell,eval_loop,3}]} ** > > I've worked around this more times than I can remember, special-casing the > zero case to avoid calling seq, and I'll bet that many callers of seq have > to do the same thing. Any chance of changing this in the future? There can't > be much code that would break... code that only works today *because* seq > raises an exception. > > John Hughes > > _______________________________________________ > erlang-bugs mailing list > erlang-bugs@REDACTED > http://www.erlang.org/mailman/listinfo/erlang-bugs > From nick@REDACTED Mon Nov 12 11:01:36 2007 From: nick@REDACTED (Niclas Eklund) Date: Mon, 12 Nov 2007 11:01:36 +0100 (MET) Subject: [erlang-bugs] Does 'ic' (the CORBA IDL compiler) support recursive types? In-Reply-To: <7732.217.128.75.198.1194626028.squirrel@www.geekisp.com> Message-ID: Hello! You're corrrect. It would also cause problems if a standard specification (e.g. from OMG, 3GPP or Parlay) is issued and it contains rescursive types. At the moment, due to lack of time, it's impopssible to say when this could be added. /Nick On Fri, 9 Nov 2007, Dominic Williams wrote: > Hi Nick, > > > After a quick search in my mail boxes I found that the last time someone > > asked about rescursive types was back in Nov 2003. As you understand, > > since it's seldom used and one can solve this in other ways, it hasn't > > been a high prio IC extension. > > I would just like to point out that this rationale only applies to > projects using > Erlang and Orber for custom CORBA interfaces (when the IDL can be > modified at will to work around an IC limitation). > > We use Erlang and Orber in a product which allows our customers to > interface with any CORBA server themselves, without coding anything. In > practice they use this to interface with legacy external systems with a > fixed, published IDL that cannot be changed. > > Luckily we have not yet come across one such IDL using recursive types, > but it would be preferable, for projects such as ours integrating Orber and > IC as a component of our product rather than using it as an internal > development tool, if IC could handle any legal IDL. > > Regards, > > Dominic Williams > http://dominicwilliams.net > > ---- From hans.bolinder@REDACTED Mon Nov 12 13:39:22 2007 From: hans.bolinder@REDACTED (Hans Bolinder) Date: Mon, 12 Nov 2007 13:39:22 +0100 Subject: [erlang-bugs] odd rr behaivor In-Reply-To: References: Message-ID: <18232.18810.235222.651786@gargle.gargle.HOWL> [Matthew O'Gorman:] > I wouldn't necessarily call this a bug, but it seems rr does not allow > for passing an atom to it in the same way, for example > > 1> ls(). > mog.hrl > ok > 2> rr(mog). > {error, nofile} > 3>rr("mog"). > [] > 4>rr("mog.hrl"). > [test] > ... Hi, Sorry for not answering sooner. rr(Atom) is essentially the same as rr(code:which(Atom)). Instead of 'rr("long_path_to_a_header_file")' it is often convenient to call 'rr(Module)' (Module an atom) where Module includes the header file. An example: instead of rr("/usr/local/lib/erlang/lib/xmerl-1.1.5/include/xmerl.hrl"). one can do rr(xmerl). Best regards, Hans Bolinder, Erlang/OTP From anders.nygren@REDACTED Thu Nov 15 17:44:51 2007 From: anders.nygren@REDACTED (Anders Nygren) Date: Thu, 15 Nov 2007 10:44:51 -0600 Subject: [erlang-bugs] R12 - Internal consistency check failed Message-ID: Using the R12 snapshot from 15-Nov-2007 12:53 I get the following error /usr/local/src/otp/otp_src_R12B-0/bin/erlc -smp wfbm4_ets.erl wfbm4_ets: function find/6+75: Internal consistency check failed - please report this bug. Instruction: {test,bs_start_match2,{f,45},[{y,7},3,0,{x,1}]} Error: {match_context,{y,7}}: make: *** [wfbm4_ets.beam] Error 1 when I compile the attached wfbm4_ets.erl /Anders -------------- next part -------------- A non-text attachment was scrubbed... Name: wfbm4_ets.erl Type: text/x-erlang Size: 3781 bytes Desc: not available URL: From bjorn@REDACTED Thu Nov 15 20:40:37 2007 From: bjorn@REDACTED (Bjorn Gustavsson) Date: 15 Nov 2007 20:40:37 +0100 Subject: [erlang-bugs] R12 - Internal consistency check failed In-Reply-To: References: Message-ID: "Anders Nygren" writes: > Using the R12 snapshot from 15-Nov-2007 12:53 I get the following error > > /usr/local/src/otp/otp_src_R12B-0/bin/erlc -smp wfbm4_ets.erl > wfbm4_ets: function find/6+75: > Internal consistency check failed - please report this bug. > Instruction: {test,bs_start_match2,{f,45},[{y,7},3,0,{x,1}]} > Error: {match_context,{y,7}}: > > make: *** [wfbm4_ets.beam] Error 1 Thanks for reporting this bug. I'll look at it at soon as possible. /Bjorn -- Bj?rn Gustavsson, Erlang/OTP, Ericsson AB From bjorn@REDACTED Thu Nov 15 22:20:59 2007 From: bjorn@REDACTED (Bjorn Gustavsson) Date: 15 Nov 2007 22:20:59 +0100 Subject: [erlang-bugs] R12 - Internal consistency check failed In-Reply-To: References: Message-ID: "Anders Nygren" writes: > Using the R12 snapshot from 15-Nov-2007 12:53 I get the following error > > /usr/local/src/otp/otp_src_R12B-0/bin/erlc -smp wfbm4_ets.erl > wfbm4_ets: function find/6+75: > Internal consistency check failed - please report this bug. > Instruction: {test,bs_start_match2,{f,45},[{y,7},3,0,{x,1}]} > Error: {match_context,{y,7}}: I've updated the test suite and fixed the bug. The fix should be included in the snapshots starting late Friday or early Saturday. /Bjorn -- Bj?rn Gustavsson, Erlang/OTP, Ericsson AB From mickael.remond@REDACTED Fri Nov 16 10:17:27 2007 From: mickael.remond@REDACTED (=?UTF-8?Q?Micka=C3=ABl_R=C3=A9mond?=) Date: Fri, 16 Nov 2007 10:17:27 +0100 Subject: [erlang-bugs] Erlang on MacOSX 10.5 Message-ID: <58FED35C-E8AC-4274-AD4B-719CB7A8D28B@process-one.net> Hello, For your information on MacOSX 10.5 OS mon does not work totally fine (at least CPU Mon) I did not look deeper into the problem yet. If you need more information I can provide that. I get the following crash: =ERROR REPORT==== 16-Nov-2007::10:13:06 === ** Generic server cpu_sup terminating ** Last message in was "f" ** When Server state == {state,not_used,[],{unix,darwin}} ** Reason for termination == ** {{badmatch,{error,{fread,float}}}, [{cpu_sup,get_int_measurement,2}, {cpu_sup,handle_call,3}, {gen_server,handle_msg,6}, {proc_lib,init_p,5}]} =CRASH REPORT==== 16-Nov-2007::10:13:06 === crasher: pid: <0.523.0> registered_name: cpu_sup error_info: {{badmatch,{error,{fread,float}}}, [{cpu_sup,get_int_measurement,2}, {cpu_sup,handle_call,3}, {gen_server,handle_msg,6}, {proc_lib,init_p,5}]} initial_call: {gen,init_it, [gen_server, <0.518.0>, <0.518.0>, {local,cpu_sup}, cpu_sup, [], []]} ancestors: [os_mon_sup,<0.517.0>] messages: [] links: [<0.518.0>] dictionary: [] trap_exit: true status: running heap_size: 610 stack_size: 21 reductions: 347 neighbours: =SUPERVISOR REPORT==== 16-Nov-2007::10:13:06 === Supervisor: {local,os_mon_sup} Context: child_terminated Reason: {{badmatch,{error,{fread,float}}}, [{cpu_sup,get_int_measurement,2}, {cpu_sup,handle_call,3}, {gen_server,handle_msg,6}, {proc_lib,init_p,5}]} Offender: [{pid,<0.523.0>}, {name,cpu_sup}, {mfa,{cpu_sup,start_link,[]}}, {restart_type,permanent}, {shutdown,2000}, {child_type,worker}] =PROGRESS REPORT==== 16-Nov-2007::10:13:06 === supervisor: {local,os_mon_sup} started: [{pid,<0.628.0>}, {name,cpu_sup}, {mfa,{cpu_sup,start_link,[]}}, {restart_type,permanent}, {shutdown,2000}, {child_type,worker}] Cheers, -- Micka?l R?mond http://www.process-one.net/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From paul-trapexit@REDACTED Mon Nov 19 20:26:58 2007 From: paul-trapexit@REDACTED (Paul Mineiro) Date: Mon, 19 Nov 2007 11:26:58 -0800 (PST) Subject: [erlang-bugs] mnesia 4.3.5 ignores module argument to mnesia:restore/2, always uses default backup module Message-ID: Patch attached. -- p Optimism is an essential ingredient of innovation. How else can the individual favor change over security? -- Robert Noyce -------------- next part -------------- --- mnesia-4.3.5/src/mnesia_schema.erl.orig 2007-03-27 06:37:32.000000000 -0700 +++ mnesia-4.3.5/src/mnesia_schema.erl 2007-11-19 11:21:04.000000000 -0800 @@ -2462,7 +2462,7 @@ InitR = #r{opaque = Opaque, module = Module}, case catch lists:foldl(fun check_restore_arg/2, InitR, Args) of R when record(R, r) -> - case mnesia_bup:read_schema(Module, Opaque) of + case mnesia_bup:read_schema(R#r.module, Opaque) of {error, Reason} -> {aborted, Reason}; BupSchema -> From opfer@REDACTED Tue Nov 20 13:48:18 2007 From: opfer@REDACTED (Christian Faulhammer) Date: Tue, 20 Nov 2007 13:48:18 +0100 Subject: [erlang-bugs] Disabled ODBC support for x86_64 Message-ID: <20071120134818.76b93489@gentoo.org> Hi, I was informed by bug tracker that the odbc support is disabled by conditionals in the Makefile for x86_64 architecture. The patch is really simple, but I'd like to know if there was a purpose to switch it off and if the purpose is still valid. The user reports that it works well on his system, and that ALT Linux' Erlang maintainers report the same success. V-Li -- Christian Faulhammer, Gentoo Lisp project , #gentoo-lisp on FreeNode -------------- next part -------------- A non-text attachment was scrubbed... Name: erlang-R11B5-amd64.patch Type: text/x-patch Size: 563 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 189 bytes Desc: not available URL: From anders.nygren@REDACTED Wed Nov 21 00:40:14 2007 From: anders.nygren@REDACTED (Anders Nygren) Date: Tue, 20 Nov 2007 17:40:14 -0600 Subject: [erlang-bugs] R12 documentation Message-ID: In the R12 documentation snapshot otp_html_R12B_2007-11-20_16.tar.gz the links to Glossary Modules Index Release highlights Potential incompatibilities opens in a new tab, or window, depending on Your browser configuration. /Anders From dgud@REDACTED Wed Nov 21 07:44:25 2007 From: dgud@REDACTED (Dan Gudmundsson) Date: Wed, 21 Nov 2007 07:44:25 +0100 Subject: [erlang-bugs] mnesia 4.3.5 ignores module argument to mnesia:restore/2, always uses default backup module In-Reply-To: References: Message-ID: <4743D3C9.1070402@erix.ericsson.se> Thanks. /Dan Paul Mineiro wrote: > Patch attached. > > -- p > > Optimism is an essential ingredient of innovation. How else can the > individual favor change over security? > > -- Robert Noyce > > > ------------------------------------------------------------------------ > > _______________________________________________ > erlang-bugs mailing list > erlang-bugs@REDACTED > http://www.erlang.org/mailman/listinfo/erlang-bugs From andy@REDACTED Thu Nov 22 00:12:34 2007 From: andy@REDACTED (Andrew Birkett) Date: Wed, 21 Nov 2007 23:12:34 +0000 Subject: [erlang-bugs] inets-4.7.16 doesn't handle HTTP 204 responses Message-ID: <4744BB62.4010009@nobugs.org> Hi, I've been writing an erlang wrapper for Amazon's S3 storage service, and I've found a problem with the way inets-4.7.16 (from otp_src_R11B-5) handles the HTTP 204 (No content) status code. I've attached a suggested patch, and also included a method of reproducing the problem. According to RFC 2616 section 4.3, a 204 response 'must not' contain an entity body. Therefore the content-length header is optional and should be ignored regardless. The erlang library wrongly tries to use the content-length header when it receives a 204 reply. If the content-length header is not present, httpc_handler tries to listen for more bytes on the socket. With a persistent HTTP connection, this means the application appears to hang. Attached is a patch against inets-4.7.16 which fixes this issue. I've only recently started using erlang, so I hope it's okay. Also, here is a way of reproducing the problem on unix using the socat utility as a mock webserver. 1. Create a 'reply-204-no-content-length' script containing the following: #!/bin/bash sleep 1 echo -ne 'HTTP/1.1 204 No Content\r\nSomeHeader: foo\r\n\r\n' sleep 100 2. Run socat tcp-listen:9999,reuseaddr exec:./reply-204 3. Evaluate: http:request(put, {"http://localhost:9999/", [{"Content-Length","1"}, {"Content-Type","text/plain"}], [], <<1>>},[],[{sync,true}]). 4. This will hang for 101 seconds. The call ultimately only returns because socat has closed the connection. With the patch applied, the call returns immediately once the HTTP reply is received. Andrew -- - http://www.nobugs.org - -------------- next part -------------- A non-text attachment was scrubbed... Name: inets-204-bug.patch Type: text/x-patch Size: 678 bytes Desc: not available URL: From ingela@REDACTED Thu Nov 22 11:27:43 2007 From: ingela@REDACTED (Ingela Anderton Andin) Date: Thu, 22 Nov 2007 11:27:43 +0100 Subject: [erlang-bugs] inets-4.7.16 doesn't handle HTTP 204 responses In-Reply-To: <4744BB62.4010009@nobugs.org> References: <4744BB62.4010009@nobugs.org> Message-ID: <4745599F.4000409@erix.ericsson.se> Hi! Thank you for reporting this bug and for the patch suggestion. I have fixed the problem in inets-5.0 that will be released in r12b early december. Regards Ingela - OTP team Andrew Birkett wrote: > Hi, > > I've been writing an erlang wrapper for Amazon's S3 storage service, > and I've found a problem with the way inets-4.7.16 (from > otp_src_R11B-5) handles the HTTP 204 (No content) status code. I've > attached a suggested patch, and also included a method of reproducing > the problem. > > According to RFC 2616 section 4.3, a 204 response 'must not' contain > an entity body. Therefore the content-length header is optional and > should be ignored regardless. > > The erlang library wrongly tries to use the content-length header when > it receives a 204 reply. If the content-length header is not present, > httpc_handler tries to listen for more bytes on the socket. With a > persistent HTTP connection, this means the application appears to hang. > > Attached is a patch against inets-4.7.16 which fixes this issue. I've > only recently started using erlang, so I hope it's okay. Also, here > is a way of reproducing the problem on unix using the socat utility as > a mock webserver. > > 1. Create a 'reply-204-no-content-length' script containing the > following: > #!/bin/bash > sleep 1 > echo -ne 'HTTP/1.1 204 No Content\r\nSomeHeader: foo\r\n\r\n' > sleep 100 > > 2. Run socat tcp-listen:9999,reuseaddr exec:./reply-204 > > 3. Evaluate: http:request(put, {"http://localhost:9999/", > [{"Content-Length","1"}, {"Content-Type","text/plain"}], [], > <<1>>},[],[{sync,true}]). > > 4. This will hang for 101 seconds. The call ultimately only returns > because socat has closed the connection. With the patch applied, the > call returns immediately once the HTTP reply is received. > > Andrew > -- > - http://www.nobugs.org - > > ------------------------------------------------------------------------ > > _______________________________________________ > erlang-bugs mailing list > erlang-bugs@REDACTED > http://www.erlang.org/mailman/listinfo/erlang-bugs From erlang@REDACTED Thu Nov 22 14:24:45 2007 From: erlang@REDACTED (Joe Armstrong) Date: Thu, 22 Nov 2007 14:24:45 +0100 Subject: [erlang-bugs] bug in binary_to_term Message-ID: <9b08084c0711220524n23635bbahbf4fd1602b22d9fa@mail.gmail.com> -module(bug). -compile(export_all). %% If you do B = term_to_binary(Term) %% and then concatinate some extra data to the end of %% B then binary_to_term of the new binary succeeds %% It should fail. %% %% You need to test that you have consumed the entire binary %% when doing binary_to_term %% %% This caused a nasty error - when two TCP packets %% became merged into one (due to packet fragmentation and recombiation) %% each packet had one term, so the second term mysteriously vanished test() -> B = term_to_binary({hello,joe}), {hello,joe} = binary_to_term(B), B1 = <<"any old junk">>, B2 = <>, {hello,joe} = binary_to_term(B2), %% <--- this should raise an exception this_should_not_be_printed_out. /Joe Armstrong From bjorn@REDACTED Thu Nov 22 14:40:35 2007 From: bjorn@REDACTED (Bjorn Gustavsson) Date: 22 Nov 2007 14:40:35 +0100 Subject: [erlang-bugs] bug in binary_to_term In-Reply-To: <9b08084c0711220524n23635bbahbf4fd1602b22d9fa@mail.gmail.com> References: <9b08084c0711220524n23635bbahbf4fd1602b22d9fa@mail.gmail.com> Message-ID: "Joe Armstrong" writes: > -module(bug). > > -compile(export_all). > > %% If you do B = term_to_binary(Term) > %% and then concatinate some extra data to the end of > %% B then binary_to_term of the new binary succeeds > %% It should fail. It is not a bug, it is a feature. It is implemented that way for historical reasons, long ago by someone at the CS lab. It can't be changed now, because there is code that depends on the old behaviour, for instance, the distribution in the emulator itself and dets (including dets files). We have actually made an attempt to fix this "bug", but failed miserably because too much code depended on it. /Bjorn -- Bj?rn Gustavsson, Erlang/OTP, Ericsson AB From n.decker@REDACTED Tue Nov 27 13:37:55 2007 From: n.decker@REDACTED (Decker, Nils) Date: Tue, 27 Nov 2007 13:37:55 +0100 Subject: [erlang-bugs] dist_ac deadlock Message-ID: <8981957283CC0F49A8E35A51B03CEECE02020AB9@s-mci-hh-02-nt.extern.studio-hamburg.de> Hello everyone, is sent this message last week, but it does not appear in the mailinglist archive. Please excuse possible duplicates. I have found a deadlock in the dist_ac process during a failover of a distributed application on 4 nodes. I am using Release R11B2 (debian stable). R11B5 (11.b.5dfsg-8 debian testing) shows the same behaviour. The situation: - 2 distributed applications defined to run on 4 nodes with the same priority. {distributed, [ {cmm_adm, [{'cmm1@REDACTED', ... 'cmm4@REDACTED'}]}, {cmm_db, [{'cmm1@REDACTED', ... 'cmm4@REDACTED'}]} ]} - takeover to node4 using application:takeover(cmm_db, permanent), same for cmm_adm - kill this node using ^C a Observations: - The application is started on node1 - application:info() shows the cmm_db application as running on node1 - application:info() on the other nodes show the applications running on the killed node - dist_ac:info() times out I generated a crashdump on node 1 - 3. dist_ac (0.17.0) on node1: - Program counter: gen_server:loop - Msg Queue Length: 0 - state of the application ( from stack ): local dist_ac (0.17.0) on node2: - Program counter: dist_ac:collect_answers/4 - Msg Queue Length: 5 {'EXIT',<0.183.0>,normal} {internal_restart_appl,cmm_adm} {'EXIT',<0.184.0>,normal} {dist_ac_weight,cmm_adm,10,'cmm1@REDACTED'} {nodedown,'cmm3@REDACTED'} - state of the application ( from stack ): {failover,'cmm4@REDACTED'}, dist_ac (0.17.0) on node3: - Program counter: dist_ac:collect_answers/4 - Msg Queue Length: 6 {'EXIT',<0.157.0>,normal} {internal_restart_appl,cmm_adm} {'EXIT',<0.158.0>,normal} {dist_ac_weight,cmm_db,10,'cmm2@REDACTED'} {dist_ac_weight,cmm_db,10,'cmm2@REDACTED'} {dist_ac_weight,cmm_adm,10,'cmm1@REDACTED'} - state of the application ( from stack ): {failover,'cmm4@REDACTED'}, The comment before the function dist_ac:collect_answers/4 states that dist_ac must always be prepared to handle dist_ac_weight messages. Yet collect_answers does not handle this message. This seems to be a problem, if more than two nodes have the same priority for an application. I have changed my application to have different priorities on the nodes. (list of nodes instead of tuple with nodes) This works but has the drawback that a takeover is performed when the failed node comes back online. (forcing the re-initialisation of the communication to a number of external systems) I could provide crashdumps or try to reproduce the error with a minimal application if needed. Regards Nils Decker -- - MCI alles aus einer Hand - _____________________________ Nils Decker Projektierung Studio Hamburg Media Consult International (MCI) GmbH Jenfelder Allee 80 22039 Hamburg phone: +49 (0)40 66 88 34 37 fax: +49 (0)40 66 88 52 22 E-mail: n.decker@REDACTED Web: www.mci-broadcast.com Gesch?ftsf?hrung: Ralf Schimmel Prokuristen: J?rn Denneborg, J?rg Pankow Amtsgericht Hamburg, HRB 70454 From stupalo@REDACTED Wed Nov 28 09:58:45 2007 From: stupalo@REDACTED (=?ISO-8859-1?Q?G=F6ran_Stupalo?=) Date: Wed, 28 Nov 2007 09:58:45 +0100 Subject: [erlang-bugs] R12 documentation In-Reply-To: References: Message-ID: <474D2DC5.8020801@erix.ericsson.se> Hi Anders, Thank you for the information. We're still working with some minor documentation tweaks, but I think that the ones mentioned below are fixed now. /G?ran Anders Nygren wrote: > In the R12 documentation snapshot otp_html_R12B_2007-11-20_16.tar.gz > the links to > Glossary > Modules > Index > Release highlights > Potential incompatibilities > > opens in a new tab, or window, depending on Your browser configuration. > > /Anders > _______________________________________________ > erlang-bugs mailing list > erlang-bugs@REDACTED > http://www.erlang.org/mailman/listinfo/erlang-bugs > -- G?ran Stupalo, Erlang/OTP, Ericsson AB From erlang@REDACTED Thu Nov 29 16:06:11 2007 From: erlang@REDACTED (Joe Armstrong) Date: Thu, 29 Nov 2007 16:06:11 +0100 Subject: [erlang-bugs] bug Message-ID: <9b08084c0711290706u149d4a15re5545b1eb40e322c@mail.gmail.com> -module(bug). -compile(export_all). start() -> lists:filter(fun is_reference/1, [1,2,3]). %% this program compiles correctly %% it should fail with a missing function %% %% seems like there is a name collision with the guard test with the same name %% /Joe From bjorn@REDACTED Thu Nov 29 16:32:03 2007 From: bjorn@REDACTED (Bjorn Gustavsson) Date: 29 Nov 2007 16:32:03 +0100 Subject: [erlang-bugs] bug In-Reply-To: <9b08084c0711290706u149d4a15re5545b1eb40e322c@mail.gmail.com> References: <9b08084c0711290706u149d4a15re5545b1eb40e322c@mail.gmail.com> Message-ID: "Joe Armstrong" writes: > -module(bug). > > -compile(export_all). > > start() -> > lists:filter(fun is_reference/1, [1,2,3]). > > %% this program compiles correctly > %% it should fail with a missing function Maybe. I am not sure whether this is a bug or a feature. I would be interested to hear more opinions about it before changing it. > %% seems like there is a name collision with the guard test with the same name Yes, the guard BIF is_reference/1 will be called, so the code will actually work. If you include a reference in the input list, it will be included in the output list. /Bjorn -- Bj?rn Gustavsson, Erlang/OTP, Ericsson AB From richardc@REDACTED Thu Nov 29 17:03:23 2007 From: richardc@REDACTED (Richard Carlsson) Date: Thu, 29 Nov 2007 17:03:23 +0100 Subject: [erlang-bugs] bug In-Reply-To: References: <9b08084c0711290706u149d4a15re5545b1eb40e322c@mail.gmail.com> Message-ID: <474EE2CB.80001@it.uu.se> Bjorn Gustavsson wrote: > "Joe Armstrong" writes: >> start() -> >> lists:filter(fun is_reference/1, [1,2,3]). >> >> %% this program compiles correctly >> %% it should fail with a missing function > > Maybe. I am not sure whether this is a bug or a feature. > ...the guard BIF is_reference/1 will be called, so the code > will actually work. If this is ok: start() -> lists:filter(fun (X) -> is_reference(X) end, [1,2,3]). i.e., if is_reference/1 is in scope, being automatically imported from the module 'erlang' (just like is_atom/1 and the rest), then your example should also be perfectly legal and well defined. (The old-style names reference/1, atom/1, etc., are however not in scope outside guards, so 'fun reference/1' should cause complaints about a missing function, unless you have defined it yourself.) /Richard From raimo+erlang-bugs@REDACTED Fri Nov 30 08:53:57 2007 From: raimo+erlang-bugs@REDACTED (Raimo Niskanen) Date: Fri, 30 Nov 2007 08:53:57 +0100 Subject: [erlang-bugs] : bug In-Reply-To: <474EE2CB.80001@it.uu.se> References: <9b08084c0711290706u149d4a15re5545b1eb40e322c@mail.gmail.com> <474EE2CB.80001@it.uu.se> Message-ID: <20071130075357.GA10179@erix.ericsson.se> My first reaction to this was that maybe is_reference/1 is autoimported, but it would be nice and clear if the "fun is_reference/1" syntax did not do autoimporting. Easier to know what you get. You can use "fun erlang:is_reference/1" if so inclined. Then again: if e.g "fun abs/1" has done autoimporting for years I can only say "fun is_reference/1" working the way Joe found out is a (mis)feature. On Thu, Nov 29, 2007 at 05:03:23PM +0100, Richard Carlsson wrote: > Bjorn Gustavsson wrote: > > "Joe Armstrong" writes: > >> start() -> > >> lists:filter(fun is_reference/1, [1,2,3]). > >> > >> %% this program compiles correctly > >> %% it should fail with a missing function > > > > Maybe. I am not sure whether this is a bug or a feature. > > ...the guard BIF is_reference/1 will be called, so the code > > will actually work. > > If this is ok: > > start() -> > lists:filter(fun (X) -> is_reference(X) end, [1,2,3]). > > i.e., if is_reference/1 is in scope, being automatically imported > from the module 'erlang' (just like is_atom/1 and the rest), then > your example should also be perfectly legal and well defined. > > (The old-style names reference/1, atom/1, etc., are however not > in scope outside guards, so 'fun reference/1' should cause complaints > about a missing function, unless you have defined it yourself.) > > /Richard > > > > > _______________________________________________ > erlang-bugs mailing list > erlang-bugs@REDACTED > http://www.erlang.org/mailman/listinfo/erlang-bugs -- / Raimo Niskanen, Erlang/OTP, Ericsson AB From erlang@REDACTED Fri Nov 30 10:28:19 2007 From: erlang@REDACTED (Joe Armstrong) Date: Fri, 30 Nov 2007 10:28:19 +0100 Subject: [erlang-bugs] : bug In-Reply-To: <20071130075357.GA10179@erix.ericsson.se> References: <9b08084c0711290706u149d4a15re5545b1eb40e322c@mail.gmail.com> <474EE2CB.80001@it.uu.se> <20071130075357.GA10179@erix.ericsson.se> Message-ID: <9b08084c0711300128w3fab4603ve2935aa52d1d37be@mail.gmail.com> Actually it was my impression that guard predicates could only occur after a "when" keyword or in an "if" and not anywhere else. This is consistent with the view that a guard is an extension of pattern matching and is there to produce better code in the pattern matcher. Guard test functions are not boolean functions which return true or false - but things which succeed or fail in pattern matching. Actually they could be overloaded so as to be interpreted as boolean functions when used in expressions. How is it today? The reference manual on the net says that guard sequences can only occur in "if" and after a when - and that guard tests are part of guard sequences. It makes no mention of them being allowed in expressions. On Nov 30, 2007 8:53 AM, Raimo Niskanen wrote: > My first reaction to this was that maybe is_reference/1 is > autoimported, but it would be nice and clear if the > "fun is_reference/1" syntax did not do autoimporting. Easier to know > what you get. You can use "fun erlang:is_reference/1" if so inclined. > > Then again: if e.g "fun abs/1" has done autoimporting > for years I can only say "fun is_reference/1" working > the way Joe found out is a (mis)feature. > > > > On Thu, Nov 29, 2007 at 05:03:23PM +0100, Richard Carlsson wrote: > > Bjorn Gustavsson wrote: > > > "Joe Armstrong" writes: > > >> start() -> > > >> lists:filter(fun is_reference/1, [1,2,3]). > > >> > > >> %% this program compiles correctly > > >> %% it should fail with a missing function > > > > > > Maybe. I am not sure whether this is a bug or a feature. > > > ...the guard BIF is_reference/1 will be called, so the code > > > will actually work. > > > > If this is ok: > > > > start() -> > > lists:filter(fun (X) -> is_reference(X) end, [1,2,3]). > > > > i.e., if is_reference/1 is in scope, being automatically imported > > from the module 'erlang' (just like is_atom/1 and the rest), then > > your example should also be perfectly legal and well defined. > > > > (The old-style names reference/1, atom/1, etc., are however not > > in scope outside guards, so 'fun reference/1' should cause complaints > > about a missing function, unless you have defined it yourself.) > > > > /Richard > > > > > > > > > > _______________________________________________ > > erlang-bugs mailing list > > erlang-bugs@REDACTED > > http://www.erlang.org/mailman/listinfo/erlang-bugs > > -- > > / Raimo Niskanen, Erlang/OTP, Ericsson AB > _______________________________________________ > erlang-bugs mailing list > erlang-bugs@REDACTED > http://www.erlang.org/mailman/listinfo/erlang-bugs > From richardc@REDACTED Fri Nov 30 11:41:21 2007 From: richardc@REDACTED (Richard Carlsson) Date: Fri, 30 Nov 2007 11:41:21 +0100 Subject: [erlang-bugs] : bug In-Reply-To: <20071130075357.GA10179@erix.ericsson.se> References: <9b08084c0711290706u149d4a15re5545b1eb40e322c@mail.gmail.com> <474EE2CB.80001@it.uu.se> <20071130075357.GA10179@erix.ericsson.se> Message-ID: <474FE8D1.6020800@it.uu.se> Raimo Niskanen wrote: > My first reaction to this was that maybe is_reference/1 is > autoimported, but it would be nice and clear if the > "fun is_reference/1" syntax did not do autoimporting. Easier to know > what you get. You can use "fun erlang:is_reference/1" if so inclined. Actually, the way it is working is precisely the way it should work, even if some of you oldtimers may find it surprising that there are parts of Erlang which actually are consistent from a language design perspective. ;-) Like I said, if a function (any function) is in scope, so that you can call it like this: B = frobnicate(X) then the form 'fun frobnicate/1' refers to the object (the function) that the name frobnicate/1 is bound to, so: F = fun frobnicate/1, B = F(X) should be exactly equivalent. Note that the 'fun' keyword is not some kind of operator here - it's just a syntactic modifier that tells the parser that what follows could be a function name. You can't write just 'frobnicate/1' in Erlang, because it would look like an atom divided by a number. But actually, what we have here is a *variable* - a symbol ('fun f/N') bound to a value (the function). In a language like ML or Haskell, or even C, you simply have the following corresponding equivalence: b = frobnicate(x) is the same as f = frobnicate, b = f(x) which surprises no one. But it is exactly the same thing that is happening in Erlang - the only difference is that you have to say 'fun frobnicate/1' because function names (variables) are composed syntactically of an atom and an integer What *would* be strange, is if you'd decide that for _some_ names (the automatically imported ones), that equivalence would not hold! /Richard From richardc@REDACTED Fri Nov 30 13:11:14 2007 From: richardc@REDACTED (Richard Carlsson) Date: Fri, 30 Nov 2007 13:11:14 +0100 Subject: [erlang-bugs] : bug In-Reply-To: <9b08084c0711300128w3fab4603ve2935aa52d1d37be@mail.gmail.com> References: <9b08084c0711290706u149d4a15re5545b1eb40e322c@mail.gmail.com> <474EE2CB.80001@it.uu.se> <20071130075357.GA10179@erix.ericsson.se> <9b08084c0711300128w3fab4603ve2935aa52d1d37be@mail.gmail.com> Message-ID: <474FFDE2.8010107@it.uu.se> Joe Armstrong wrote: > Actually it was my impression that guard predicates could only occur > after a "when" keyword or in an "if" and not anywhere else. This is > consistent with the view that a guard is an extension of pattern matching > and is there to produce better code in the pattern matcher. > [...] > How is it today? The reference manual on the net says that guard > sequences can only occur in "if" and after a when - and that guard tests > are part of guard sequences. It makes no mention of them being allowed in > expressions. There are some concepts that need to be properly distinguished: 1. Syntax: "guard", "guard sequence", "guard test" It is quite correct that syntactically, a guard sequence can only occur as part of a clause (function, case, if, receive, try) and only after a 'when' keyword. ("guard" := 'when' "guard sequence") "guard test" is in part a syntactic concept - it refers to the individual elements (expressions) in a guard sequence, more precisely to the outermost operator of each such expression. 2. Scope: which names are defined where, and what semantic objects do they refer to? In Erlang, a special rule says that in "guard test" context (syntactically), some special names are defined which override any other definitions of those name in the current scope. These are the "old-style" type tests: integer/1, atom/1, etc. Originally, there was no way of accessing these functions except from a guard. For some strange reason, though, you have always been able to use the tests '=:=', '<', '=<', etc., even outside "guard test" context. Did you forget to disallow them in normal expressions? ;-) 3. Semantics: regardless of what name you use to identify an operation, what does it do? It was not possible, because of the name clashes it would cause, to make the type tests available in normal expressions under the same names as in guard test context (like you could for '<'), so new names had to be introduced. These are the 'is_atom/1' etc., but they are just names: they refer to the same operations as the old guard-context-only names 'atom/1' etc. If you use the new names they can be accessed everywhere. They also have a home: they live in the 'erlang' module, along with '+'/2, '<'/2, etc. So, in summary, if you call 'is_atom/1' from any Erlang expression, you are _not_ "using a guard test". You are calling a built-in boolean predicate, which also happens to be _allowed_ in a guard test context. It is all much simpler if you look at it from that angle. /Richard