io:getline(Prompt) in spawned process: Prompt does not display - erlang

Here's the code:
-module(my).
-compile(export_all).
test() ->
register(go, spawn(my, init, []) ).
init() ->
Reply = io:get_line("enter:"),
io:format("Reply= ~s~n", [Reply]).
In the shell:
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> my:test().
true
3>
If I add a timer:sleep() here:
test() ->
register(go, spawn(my, init, []) ).
init() ->
timer:sleep(1000), %%<<<==========HERE
Reply = io:get_line("enter:"),
io:format("Reply= ~s~n", [Reply]).
and run the new code in the shell, then after 1 second the shell prompt 3> in the first example's output suddenly disappears and is replaced by enter::
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> my:test().
true
enter:
And if I enter something, then as expected I see Reply= xx.
If I move the timer:sleep() to here:
test() ->
register(go, spawn(my, init, []) ),
timer:sleep(1000). %%<<======HERE
init() ->
Reply = io:get_line("enter:"),
io:format("Reply= ~s~n", [Reply]).
and I run the code in the shell, I see:
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> my:test().
enter:
then enter: suddently disappears and is replaced by ok:
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> my:test().
ok
3>
This does work as expected:
1> Reply = io:get_line("enter: ").
enter: hello
"hello\n"
2> Reply.
"hello\n"
3>
Can someone explain what race condition is occurring in the first example?

Actually this is not exactly race condition. The issue is raised from fact that we have only one std_in stream and only one process in given time can use it.
1) In first code snippet process 'go' takes control on std_in with get_line/1 function first. But after that test/0 function returns to Erlang shell and shell takes control under std_in (Erlang shell is waiting for user input with prompt like ">"). So process 'go' now unlinked from std_in and does not receive any chars from std_in. All input goes to Erlang shell.
2) Second snippet has sleep/1 function in init/1. So situation is opposite. We allow Erlang shell reach waiting for input status and AFTER that execute get_line/1 in 'go' process. So now 'go' process takes control on std_in and receives chars from keyboard. But after 'go' process terminates then Erlang shell restores its state.
3) Third snippet is just 1st but aggravate situation with sleep/1 function.
4) Nothing explain for forth snippet. It works as expected.
5) To illustrate this point of view you can run code below:
-module(my).
-compile(export_all).
test() ->
spawn_link(my, init1, []),
spawn_link(my, init2, []).
init1() ->
timer:sleep(100),
init(0, "0").
init2() ->
timer:sleep(100),
init(0, "1").
init(N, Title) ->
% io:format(">>init(~p)~n", [N]),
Reply = io:get_line(Title ++ "> enter:"),
io:format("[~s] (e - exit) Reply= ~s", [Title, Reply]),
case Reply of
"e\n" -> ok;
_ -> init(N+1, Title)
end.
The module starts two processes with get_line/1. But only one process can except input from std_in in recent moment:
50> my:test().
<0.192.0>
1> enter:w
[1] (e - exit) Reply= w
1> enter:d
[1] (e - exit) Reply= d
1> enter:e
[1] (e - exit) Reply= e
0> enter:dd
[0] (e - exit) Reply= dd
0> enter:e
[0] (e - exit) Reply= e
51>

Related

How do i implement Erlang intermodule communication using import or exref

I cannot import and therefore cannot call a function of another module in my 'main' module. I am an Erlang newbie. Below is my 'main' module.
-module('Sysmod').
-author("pato").
%% API
-export([ hello_world/0,sayGoodNight/0]).
-import('Goodnight',[sayGoodNight/0]).
hello_world()->
io:fwrite("Hello World\n").
Below is the other module which is being imported.
-module('Goodnight').
-author("pato").
%% API
-export([sayGoodNight/0]).
sayGoodNight() ->
io:format("Good night world\n").
I cannot even compile my 'main' module(Sysmod), once I export the imported function, as it throws an undefined shell command error. It compiles when I have imported the module and function, but cannot execute the function and it throws a undefined function error. I have checked out [this answer]1 and also looked at [erlang man pages on code server]2.
In addition, I managed to add_path of the Erlang Decimal library successfully as below attempting my app to talk to an external library.
12> code:add_path("/home/pato/IdeaProjects/AdminConsole/erlang-decimal-master/ebin"). true
But cannot run any Decimal function successfully as shown below.
decimal:add("1.3", "1.07").** exception error: undefined function decimal:add/2
In short, the first method,(I know its not recommended due to unreadability) of intermodule communication using import is not working. As I looked for a solution, I realized the add-path only works with modules that have an ebin directory.
I am stuck. How do I make my modules talk to each other including an external library added successfully by add_path? I have heard of exref, i cannot grasp the Erlang man pages. I need someone to explain it to me like a five year old. Thank you.
I am an Erlang newbie
Don't use import. No one else does. It's bad programming practice. Instead, call functions by their fully qualified names, i.e. moduleName:functionName
throws a undefined function error
You didn't compile the module you are trying to import. Also, you can't export a function that is not defined within a module.
Here's an example:
~/erlang_programs$ mkdir test1
~/erlang_programs$ cd test1
~/erlang_programs/test1$ m a.erl %%creates a.erl
~/erlang_programs/test1$ cat a.erl
-module(a).
-compile(export_all).
go()->
b:hello().
~/erlang_programs/test1$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
2> a:go().
** exception error: undefined function b:hello/0
3>
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
(v)ersion (k)ill (D)b-tables (d)istribution
~/erlang_programs/test1$ mkdir test2
~/erlang_programs/test1$ cd test2
~/erlang_programs/test1/test2$ m b.erl %%creates b.erl
~/erlang_programs/test1$ cat b.erl
-module(b).
-compile(export_all).
hello() ->
io:format("hello~n").
~/erlang_programs/test1/test2$ erlc b.erl
b.erl:2: Warning: export_all flag enabled - all functions will be exported
~/erlang_programs/test1/test2$ ls
b.beam b.erl
~/erlang_programs/test1/test2$ cd ..
~/erlang_programs/test1$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
2> a:go().
** exception error: undefined function b:hello/0
3> code:add_path("./test2").
true
4> a:go().
hello
ok

What is the difference between compile(export_all) and export([all/0]) in Erlang?

Seems like the two has the same effect when used as in all of the functions are exported when you compile your code. Is there a difference between the two ? Does export([all/0]). export all of the functions without needing to be compiled ?
I read Pouriya's answer several times, and it wasn't until I read it the third time that I understood what Pouriya was trying to say.
What Pouriya is trying to say is that export([all/0]) doesn't do what you think it does. Rather, it exports a single function named all(), and no other functions in the module will be exported. That is simple to test:
-module(my).
-export([all/0]).
all() -> ok.
go() -> ok.
In the shell:
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(my).
my.erl:5: Warning: function go/0 is unused
{ok,my}
Right away you get a warning: because go() isn't exported, which means you can't call it from outside the module, and because no functions inside the module call go(), the function go() is "unused". In other words, go() will never execute, so the compiler is wondering why you defined go() in the first place.
But, suppose you can't figure out what that warning means (and after all it's just a warning):
2> my:all().
ok
3> my:go().
** exception error: undefined function my:go/0
Seems like the two has the same effect
Nope:
-module(my).
-compile([export_all]).
all() -> ok.
go() -> ok.
In the shell:
/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2>
No warning about go() being "unused". And:
2> my:all().
ok
3> my:go().
ok
4>
no error when you call go().

How to get AST (Abstract Syntax Tree) of an Erlang local fun?

For some Erlang terms for example atom, tuple, list i can get AST using erl_parse:abstract/1. But it does not work for funs.
~ $ erl
Erlang/OTP 19 [erts-8.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.0 (abort with ^G)
1> erl_parse:abstract(foo).
{atom,0,foo}
2> erl_parse:abstract([bar]).
{cons,0,{atom,0,bar},{nil,0}}
3> erl_parse:abstract({baz}).
{tuple,0,[{atom,0,baz}]}
4> erlang:fun_info(fun() -> ok end, type).
{type,local} % So this is a local fun
5> erl_parse:abstract(fun() -> ok end).
** exception error: no function clause matching
erl_parse:abstract(#Fun<erl_eval.20.52032458>,0,
#Fun<erl_parse.3.3133389>) (erl_parse.yrl, line 1330)
I know that some local funs have their AST in their info. But this is not for all local funs.
~ $ erl
Erlang/OTP 19 [erts-8.0] [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V8.0 (abort with ^G)
1> erlang:fun_info(fun() -> ok end, env).
{env,[{[],
{eval,#Fun<shell.21.31625193>},
{value,#Fun<shell.5.31625193>},
[{clause,1,[],[],[{atom,1,ok}]}]}]} %% Here
2> foo:test(). %% Yields a fun
#Fun<foo.0.10202683>
3> erlang:fun_info(foo:test(), type).
{type,local} %% So this is a local fun too
4> erlang:fun_info(foo:test(), env).
{env,[]} %% : (
Getting AST of an external fun is not hard. my solution is to load its module beam chunks and get AST of that function. If you have better solution, please tell me. The main problem is for getting AST of local funs.
Maybe you can try also combine erl_scan:string/1 and erl_parse:parse_exprs/1, eg:
1> Fun = "fun() -> ok end.".
"fun() -> ok end."
2> {ok, Tokens, _EndLocation} = erl_scan:string(Fun).
{ok,[{'fun',1},
{'(',1},
{')',1},
{'->',1},
{atom,1,ok},
{'end',1},
{dot,1}],
1}
3> {ok, ExprList} = erl_parse:parse_exprs(Tokens).
{ok,[{'fun',1,{clauses,[{clause,1,[],[],[{atom,1,ok}]}]}}]}
Hope, this will be helpful.
erl_parse:abstract/1 cannot accept function object as argument. I think you are right in the rest.

How do unix domain sockets work in Erlang 19

I tried a few things but I'm not able to read anything from them
{ok, Port} = gen_udp:open(0, [{ifaddr,{local,"/tmp/socket2"}}]).
Then I switch to console.
echo "hi" | socat - UNIX-CONNECT:/tmp/socket2
Back to erlang
41> gen_udp:recv(Port, 2, 5000).
{error,timeout}
Any help is appreciated. I've also tried {active, true} opt and flush(). shows nothing.
I've not tried the official release 19, but I can make it work using the latest git (as of July 7th) by:
disabling active with {active, false}
using UNIX-SENDTO instead of UNIX-CONNECT
binding socat's socket to its own address (not binding creates an error on erlangs side when resolving the address.)
Demonstration:
console 1:
$ rm /tmp/socket*
$ erl
Erlang/OTP 19 [erts-8.0.1] [source-ca40008] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.0.1 (abort with ^G)
1> {ok, Port} = gen_udp:open(0, [{active, false},{ifaddr, {local,"/tmp/socket2"}}]),
1> io:format("ok~w ~w~n", [ok,Port]),
1> gen_udp:recv(Port, 2).
okok #Port<0.451>
console 2:
$ echo "hi" | socat - UNIX-SENDTO:/tmp/socket2,bind=/tmp/socket1
console 1 results:
okok #Port<0.451>
{ok,{{local,<<"/tmp/socket1">>},0,"hi\n"}}

Pid as erlang maps key?

Can Pid be maps key ?
Build maps from #{} syntax, The error says Pid can not be key.
Bug build with maps module, Pid can be key.
18>
18> Pid = self().
<0.39.0>
19> #{Pid => 1}.
* 1: illegal use of variable 'Pid' in map
20>
20> M1 = maps:from_list([{Pid, 1}]).
#{<0.39.0> => 1}
21>
21> #{Pid := V} = M1.
* 2: illegal use of variable 'Pid' in map
22>
22> maps:get(Pid, M1).
1
Support for arbitrary keys in map patterns is already available in "Erlang 18 (release candidate 2)".
$ erl
Erlang/OTP 18 [RELEASE CANDIDATE 2] [erts-7.0] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V7.0 (abort with ^G)
1> Pid = self().
<0.33.0>
2> #{Pid => 1}.
#{<0.33.0> => 1}
The problem doesn't come from the usage of pid, but from the usage of a variable as a key in the map definition. It is not yet implemented (and don't know when it could be done).

Resources