Can Erlang source code be embedded in Elixir code? If so, how? - erlang

Elixir source may be injected using Code.eval_string/3. I don't see mention of running raw Erlang code in the docs:
https://hexdocs.pm/elixir/Code.html#eval_string/3
I am coming from a Scala world in which Java objects are callable using Scala syntax, and Scala is compiled into Java and visible by intercepting the compiler output (directly generated with scalac).
I get the sense that Elixir does not provide such interoperating features, nor allow injection of custom Erlang into the runtime. Is this the case?

You can use the erlang standard library modules from Elixir, as described here or here.
For example:
def random_integer(upper) do
:rand.uniform(upper) # rand is an erlang library
end
You can also add erlang packages to your mix.exs dependencies and use them in your project, as long as these packages are published on hex or on github.
You can also use erlang and elixir code together in a project as described here.
So yeah, it's perfectly possible to call erlang code from elixir.
Vice-versa is also possible, see here for more information:
Elixir compiles into BEAM byte code (via Erlang Abstract Format). This
means that Elixir code can be called from Erlang and vice versa,
without the need to write any bindings.

Expanding what #zwippie have written:
All remote function calls (by that I mean calling function with explicitly set module/alias) are in form of:
<atom with module name>.<function name>(<arguments>)
# Technically it is the same as:
# apply(module, function_name_as_atom, [arguments])
And all "upper case module names" in Elixir are just atoms:
is_atom(Foo) == true
Foo == :"Elixir.Foo" # => true
So from Elixir viewpoint there is no difference between calling Erlang functions and Elixir functions. It is just different atom passed as the receiving module.
So you can easily call Erlang modules from Elixir. That mean that without much of the hassle you should be able to compile Erlang AST from within Elixir as well:
"rand:uniform(100)"
|> :merl.quote()
|> :erl_eval.expr(#{})
No need for any mental translation.
Additionally you can without any problems mix Erlang and Elixir code in single Mix project. With tree structure like:
.
|`- mix.exs
|`- src
| `- example.erl
`- lib
`- example.ex
Where example.erl is:
-module(example).
-export([hello/0]).
hello() -> <<"World">>.
And example.ex:
defmodule Example do
def print_hello, do: IO.puts(:example.hello())
end
You can compile project and run it with
mix run -e "Example.print_hello()"
And see that Erlang module was successfully compiled and executed from within Elixir code in the same project without problems.

One more thing to watch for when calling erlang code from elixir. erlang uses charlists for strings. When you call a erlang function that takes a string, convert the string to a charlist and convert returned string to a string.
Examples:
iex(17)> :string.to_upper "test"
** (FunctionClauseError) no function clause matching in :string.to_upper/1
The following arguments were given to :string.to_upper/1:
# 1
"test"
(stdlib 3.15.1) string.erl:2231: :string.to_upper/1
iex(17)> "test" |> String.to_charlist() |> :string.to_upper
'TEST'
iex(18)> "test" |> String.to_charlist() |> :string.to_upper |> to_string
"TEST"
iex(19)>

Related

luaL_loadbufferx returns syntaxerrors

I'm working on a personal project and I'm trying to get Lua to work on my embedded device.
I have my own simple file system that works with the the flash drive, and now I'm trying to use modules for the lua scripts that I run on the device.
I have edited linit.c, to make it also load the modules that are existing in the flash drive, and it works for a few modules, but for most of them it just gives me a syntax error when it parses the contents of the module. I have a lua interpreter running on my Windows machine and the code I'm writing is syntactically correct and works, and the Lua API that I use is of the same version 5.4 on the device.
These are the arguments I pass to
luaL_loadbufferx(L, luaCFunction, sizeOfModule, moduleName, "t")
where, L is the lua state, luaCFunction is the lua module wrapped in a C-style return statement, sizeOfModule, moduleName and t is selfexplanatory.
Right now luaL_loadbufferx is called in a loop for every module in my flash-drive, I have overwritten the openf function from the Lua API for these external modules.
This below is one of the examples of a module that gives me
"Syntax Error: PANIC, unprotected error in call to Lua API
[string "module"]:3: '(' expected near 'writeobj'"
File: module.lua
Contents:
function writeobj()
print('Hello World')
end
File: run.lua
Contents:
require ('module')
writeobj()
Does anyone know why this happens or did I not provide sufficient information? Please let me know.
The problem was that I thought the modules passed to the buffer had to be of the LuaToC form, i.e. "return { ...luamodule...}", but changing it to pass the module only to loadbuffer was sufficient enough because it covers the case of it not being in a C style return format.

How do I get the exported types of an erlang module?

I had cause to check the types exported by a module, and I immediately thought "right, module_info then" but was surprised to run into a few difficulties. I found I can get the exported types from modules I compile, but not from say modules in stdlib.
My (three) questions are, how do I reliably get the exported types of a module, why are the exported types in the attributes bit of the module info on some modules, and why some modules and not others?
I discovered that if I build this module:
-module(foo).
-export([bar/0]).
-export_types([baz/0]).
bar() -> bat .
And then use foo:module_info/0, I get this:
[{exports,[{bar,0},{module_info,0},{module_info,1}]},
{imports,[]},
{attributes,[{vsn,[108921085595958308709649797749441408863]},
{export_types,[{baz,0}]}]},
{compile,[{options,[{outdir,"/tmp"}]},
{version,"5.0.1"},
{time,{2015,10,22,10,38,8}},
{source,"/tmp/foo.erl"}]}]
Great, hidden away in 'attributes' is 'export_types'. Why this is in attributes I'm not quite sure, but... whatever...
I now know this will work:
4> lists:keyfind(export_types, 1, foo:module_info(attributes)).
{export_types,[{baz,0}]}
Great. So, I now know this will work:
5> lists:keyfind(export_types, 1, ets:module_info(attributes)).
false
Ah... it doesn't.
I know there are exported types of course, if the documentation isn't good enough the ets source shows:
-export_type([tab/0, tid/0, match_spec/0, comp_match_spec/0, match_pattern/0]).
In fact the exported type information for the ets module doesn't seem to be anywhere in the module info:
6> rp(ets:module_info()).
[{exports,[{match_spec_run,2},
{repair_continuation,2},
{fun2ms,1},
{foldl,3},
{foldr,3},
{from_dets,2},
{to_dets,2},
{test_ms,2},
{init_table,2},
{tab2file,2},
{tab2file,3},
{file2tab,1},
{file2tab,2},
{tabfile_info,1},
{table,1},
{table,2},
{i,0},
{i,1},
{i,2},
{i,3},
{module_info,0},
{module_info,1},
{tab2list,1},
{match_delete,2},
{filter,3},
{setopts,2},
{give_away,3},
{update_element,3},
{match_spec_run_r,3},
{match_spec_compile,1},
{select_delete,2},
{select_reverse,3},
{select_reverse,2},
{select_reverse,1},
{select_count,2},
{select,3},
{select,2},
{select,1},
{update_counter,3},
{slot,2},
{safe_fixtable,2},
{rename,2},
{insert_new,2},
{insert,2},
{prev,2},
{next,2},
{member,2},
{match_object,3},
{match_object,2},
{match_object,1},
{match,3},
{match,2},
{match,1},
{last,1},
{info,2},
{info,1},
{lookup_element,3},
{lookup,2},
{is_compiled_ms,1},
{first,1},
{delete_object,2},
{delete_all_objects,1},
{delete,2},
{delete,1},
{new,2},
{all,0}]},
{imports,[]},
{attributes,[{vsn,[310474638056108355984984900680115120081]}]},
{compile,[{options,[{outdir,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/../ebin"},
{i,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/../include"},
{i,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/../../kernel/include"},
warnings_as_errors,debug_info]},
{version,"5.0.1"},
{time,{2014,7,25,16,54,59}},
{source,"/tmp/buildd/erlang-17.1-dfsg/lib/stdlib/src/ets.erl"}]}]
ok
I took things to extremes now and ran this, logging the output to a file:
rp(beam_disasm:file("/usr/lib/erlang/lib/stdlib-2.1/ebin/ets.beam")).
Not that I don't consider this absurd... but anyway, it's about 5,000 lines of output, but nowhere do I find an instance of the string "tid".
Up to Erlang 18 this information is not easily available.
Dialyzer, for example, extracts it from the abstract syntax tree of the core Erlang version of a module (see e.g. dialyzer_utils:get_record_and_type_info/1 used by e.g. dialyzer_analysis_callgraph:compile_byte/5)
Regarding this part:
why are the exported types in the attributes bit of the module info on some modules, and why some modules and not others?
this is due to a bad definition in your module. The attribute should be -export_type, not -export_types. If you use the correct one (and define the baz/0 type and use it somewhere so that the module compiles), the exported types... vanish, as is expected.

How to parse a Haskell file without making it a module

I've just started writing a Haskell program to golf Haskell programs (minimize the number of characters), but I'm running into a parsing problem. When I use the parseModule function from Language.Haskell.Parser, it adds a module declaration to the file. Obviously, this is not what I want because it adds unnecessary characters!
So, for a program containing some code represented by ..., the output would be this.
module Main (main) where { main = do { ... }}
Is there a simple solution to this, or would I have to modify the HsModule returned from parseModule to output a file without a module declaration?

What kind of types can be sent on an Erlang message?

Mainly I want to know if I can send a function in a message in a distributed Erlang setup.
On Machine 1:
F1 = Fun()-> hey end,
gen_server:call(on_other_machine,F1)
On Machine 2:
handler_call(Function,From,State) ->
{reply,Function(),State)
Does it make sense?
Here's an interesting article about "passing fun's to other Erlang nodes". To resume it briefly:
[...] As you might know, Erlang distribution
works by sending the binary encoding
of terms; and so sending a fun is also
essentially done by encoding it using
erlang:term_to_binary/1; passing the
resulting binary to another node, and
then decoding it again using
erlang:binary_to_term/1.[...]
This is pretty obvious
for most data types; but how does it
work for function objects?
When you encode a fun, what is encoded
is just a reference to the function,
not the function implementation.
[...]
[...]the definition of the function is not passed along; just exactly enough information to recreate the fun at an other node if the module is there.
[...] If the module containing the fun has not yet been loaded, and the target node is running in interactive mode; then the module is attempted loaded using the regular module loading mechanism (contained in the module error_handler); and then it tries to see if a fun with the given id is available in said module. However, this only happens lazily when you try to apply the function.
[...] If you never attempt to apply the function, then nothing bad happens. The fun can be passed to another node (which has the module/fun in question) and then everybody is happy.
Maybe the target node has a module loaded of said name, but perhaps in a different version; which would then be very likely to have a different MD5 checksum, then you get the error badfun if you try to apply it.
I would suggest you to read the whole article, cause it's extremely interesting.
You can send any valid Erlang term. Although you have to be careful when sending funs. Any fun referencing a function inside a module needs that module to exist on the target node to work:
(first#host)9> rpc:call(second#host, erlang, apply,
[fun io:format/1, ["Hey!~n"]]).
Hey!
ok
(first#host)10> mymodule:func("Hey!~n").
5
(first#host)11> rpc:call(second#host, erlang, apply,
[fun mymodule:func/1, ["Hey!~n"]]).
{badrpc,{'EXIT',{undef,[{mymodule,func,["Hey!~n"]},
{rpc,'-handle_call_call/6-fun-0-',5}]}}}
In this example, io exists on both nodes and it works to send a function from io as a fun. However, mymodule exists only on the first node and the fun generates an undef exception when called on the other node.
As for anonymous functions, it seems they can be sent and work as expected.
t1#localhost:
(t1#localhost)7> register(shell, self()).
true
(t1#localhost)10> A = me, receive Fun when is_function(Fun) -> Fun(A) end.
hello me you
ok
t2#localhost:
(t2#localhost)11> B = you.
you
(t2#localhost)12> Fn2 = fun (A) -> io:format("hello ~p ~p~n", [A, B]) end.
#Fun<erl_eval.6.54118792>
(t2#localhost)13> {shell, 't1#localhost'} ! Fn2.
I am adding coverage logic to an app built on riak-core, and the merge of results gathered can be tricky if anonymous functions cannot be used in messages.
Also check out riak_kv/src/riak_kv_coverage_filter.erl
riak_kv might be using it to filter result, I guess.

How to distinguish ERTS versions at pre-processing time?

In the recent Erlang R14, inets' file httpd.hrl has been moved from:
src/httpd.hrl
to:
src/http_server/httpd.hrl
The Erlang Web framework includes the file in several places using the following directive:
-include_lib("inets/src/httpd.hrl").
Since I'd love the Erlang Web to compile with both versions of Erlang (R13 and R14), what I'd need ideally is:
-ifdef(OLD_ERTS_VERSION).
-include_lib("inets/src/httpd.hrl").
-else.
-include_lib("inets/src/http_server/httpd.hrl").
-endif.
Even if it possible to retrieve the ERTS version via:
erlang:system_info(version).
That's indeed not possible at pre-processing time.
How to deal with these situations? Is the parse transform the only way to go? Are there better alternatives?
Not sure if you'll like this hackish trick, but you could use a parse transform.
Let's first define a basic parse transform module:
-module(erts_v).
-export([parse_transform/2]).
parse_transform(AST, _Opts) ->
io:format("~p~n", [AST]).
Compile it, then you can include both headers in the module you want this to work for. This should give the following:
-module(test).
-compile({parse_transform, erts_v}).
-include_lib("inets/src/httpd.hrl").
-include_lib("inets/src/http_server/httpd.hrl").
-export([fake_fun/1]).
fake_fun(A) -> A.
If you're on R14B and compile it, you should have the abstract format of the module looking like this:
[{attribute,1,file,{"./test.erl",1}},
{attribute,1,module,test},
{error,{3,epp,{include,lib,"inets/src/httpd.hrl"}}},
{attribute,1,file,
{"/usr/local/lib/erlang/lib/inets-5.5/src/http_server/httpd.hrl",1}},
{attribute,1,file,
{"/usr/local/lib/erlang/lib/kernel-2.14.1/include/file.hrl",1}},
{attribute,24,record,
{file_info,
[{record_field,25,{atom,25,size}},
{record_field,26,{atom,26,type}},
...
What this tells us is that we can use both headers, and the valid one will automatically be included while the other will error out. All we need to do is remove the {error,...} tuple and get a working compilation. To do this, fix the parse_transform module so it looks like this:
-module(erts_v).
-export([parse_transform/2]).
parse_transform(AST, _Opts) ->
walk_ast(AST).
walk_ast([{error,{_,epp,{include,lib,"inets/src/httpd.hrl"}}}|AST]) ->
AST;
walk_ast([{error,{_,epp,{include,lib,"inets/src/http_server/httpd.hrl"}}}|AST]) ->
AST;
walk_ast([H|T]) ->
[H|walk_ast(T)].
This will then remove the error include, only if it's on the precise module you wanted. Other messy includes should fail as usual.
I haven't tested this on all versions, so if the behaviour changed between them, this won't work. On the other hand, if it stayed the same, this parse_transform will be version independent, at the cost of needing to order the compiling order of your modules, which is simple enough with Emakefiles and rebar.
If you are using makefiles, you can do something like
ERTS_VER=$(shell erl +V 2>&1 | egrep -o '[0-9]+.[0-9]+.[0-9]+')
than match the string and define macro in erlc arguments or in Emakefile.
There is no other way, AFAIK.

Resources