how to define and use a compile time macro? - erlang

I'm trying to understand more about settings macros for compilation.
The Erlang compile documentation shows that a macro can be defined:
{d,Macro} {d,Macro,Value}
Defines a macro Macro to have the value Value.
Macro is of type atom, and Value can be any term.
The default Value is true.
I'm trying to set a macro using a directive:
-module(my_mod).
-compile([debug_info, {d, debug_level, 1}]).
...
How would I use this macro in my code? For example I have tried this:
my_func() ->
if
debug_level == 1 -> io:format("Warning ...");
true -> io:format("Error ...")
end.
But 'Error ...' is always output.
Where am I going wrong?

You can set a macro in your code using -define:
-define(debug_level, 1).
If you want to be able to override it from the compilation command line, you can wrap it with -ifndef:
-ifndef(debug_level).
-define(debug_level, 1).
-endif.
This way, if you compile with
erlc -Ddebug_level=2 file.erl
for example, then the macro will have the value 2 instead of the default value 1.
To access the value of a macro, you prepend it with a ?:
my_func() ->
if
?debug_level == 1 -> io:format("Warning ...");
true -> io:format("Error ...")
end.
Note that since ?debug_level is a constant, you'll get compiler warnings from the if expression about clauses that can never match.

Related

Make Custom SwiftLint action regex ignore comments

I have a custom SwiftLint action to flag up print() statements:
custom_rules:
disable_print:
included: ".*\\.swift"
name: "print usage"
regex: "((\\bprint)|(Swift\\.print))\\s*\\("
message: "Don't use print"
severity: error
It works but it also flags whenever I have a print() statement specified in a documentation comment like this:
/// some comment mentioning print("hello") <- Error here
func myFunc() {}
How can I alter the regex so it ignores the print statement whenever it's in a documentation comment?
It seems that a custom rule can specify what type of code will match. The property is called match_kinds, example from Swiftlint Readme:
match_kinds: # SyntaxKinds to match. optional.
- comment
- identifier
Specifying identifier should be enough for your use case.

Function overlapping specs

I have a simple function like this:
def extract_text({_, _, [text]}) when is_binary(text), do: text
def extract_text(_), do: nil
and the spec I added for it was:
#spec extract_text(any) :: nil
#spec extract_text({any, any, [text]}) :: text when text: String.t
but when I run dializer, I get the following error:
lib/foo/bar.ex:1: Overloaded contract for
'Elixir.Foo.Bar':extract_text/1 has overlapping domains;
such contracts are currently unsupported and are simply ignored
I think I understand the reason for it but I can't really come up with a solution. What would be the right spec for this function?
You should be aware of that, even if you define multiple functions of the same arity (accept the same number of arguments), from outside world this is considered only one function. That means, you need to define function signature, and only this one should have type spec defined.
Try the following:
#spec extract_text(any) :: String.t | nil
def extract_text(arg)
def extract_text({_, _, [text]}) when is_binary(text), do: text
def extract_text(_), do: nil

syntax function into Erlang

I have a module which written into notepad:
-module(hhfuns).
-compile(export_all).
one() -> 1.
two() -> 2.
add(X,Y) - X() + Y().
and I save it as hhfuns.erl. When I run Ok then I called:
hhfuns:add(myfun hhfun:one/0, myfun hhfun:two/0).
this command make syntax error. But when I changed myfun to fun it worked.maybe it's a basic syntax but I'm new at Erlang, so please explain for me why.
When you are passing function from outside module as a parameter you should use syntax fun Module:Function/Arity. Correct version for you will be hhfuns:add(fun hhfun:one/0, fun hhfun:two/0). fun here is a required keyword and you can not use myfun here instead.
In fact myfun is not an Erlang keyword, whereas fun is.

unknow erlang syntax

In the file of "jobs_info.erl" of github project "jobs", it contains the following codes:
pp(L) when is_list(L) ->
[pp(X) || X <- L];
pp(X) ->
case '#is_record-'(X) of %<=========What's meaning of '"#is_record-'?
true ->
RecName = element(1,X),
{RecName, lists:zip(
'#info-'(RecName,fields), %<=======what's meaning of ''#info-'?
pp(tl(tuple_to_list(X))))};
false ->
if is_tuple(X) ->
list_to_tuple(pp(tuple_to_list(X)));
true ->
X
end
end.
What's the expression of '#is_record-' and ''#info-'?
"is_record" may be refered to erlang:is_record?
But what's "'#info-'"?
As Kemal points out have a look at the method declaration at github.com/esl/parse_trans/blob/master/src/exprecs.erl#L116.
If it is the ' that confuses you, remember that a function name in Erlang is an atom and that an atom needs to start with a lower-case letter and if it does not it should be surrounded by '. Check the docs for more info.

In Erlang, how do you invoke a function dynamically?

I want to call xyz with the name of a function to be invoked.
-module(sample).
-export([xyz/1]).
xyz(Name) -> Name().
p() -> "you called p".
g() -> "you called g".
But I get the following error:
1> c(sample.erl).
./sample.erl:6: Warning: function p/0 is unused
./sample.erl:7: Warning: function g/0 is unused
{ok,sample}
2> sample:xyz('p').
** exception error: bad function p
in function sample:xyz/1
3>
It is correct that you have to export p and g. You can then use apply/3 to call it.
erlang:apply(sample, p, []).
Only fun-values are usable with the Fun(...) syntax. You are passing in an atom-value. An atom is a 'bad function' as the error message go. You could do something similar to
xyz(p) -> fun p/0;
xyz(g) -> fun g/0.
Then go ahead and call
Fun = xyz(p),
Fun()
-module(sample).
-export([xyz/1, p/0, g/0]).
xyz(Name) -> ?MODULE:Name().
p() -> "you called p".
g() -> "you called g".
1> sample:xyz(p).
"you called p"
Pattern match is the idiom to use:
-module(sample).
-export([xyz/1]).
xyz(p) -> p();
xyz(q) -> g().
p() -> "you called p".
g() -> "you called g".
If you want to be dynamic you can use a gen_event server.
Essentially what this is is a server that holds a state which consists of key/function pair like so:
[{p, #func1},
{g, #func2},
{..., ...},
...]
You can then essentially bind events to functions. (there is, needless to say, a bit more to it than that.
The easiest way to do is to try exporting p and g along with xyz.
-export([xyz/1, p/0,g/0]).
After exporting the function p and g can be called as follows :
1> sample:xyz(fun sample:p/0).
"you called p"
2> sample:xyz(fun sample:g/0).
"you called g"
Another way to look at it is that (depending on the problem you're solving) dynamic calls to functions isn't necessarily the right approach. Given that processes and message passing are the way you organize your code in Erlang since it's a "concurrency oriented language", maybe you could just use message passing with a selective receive rather than mimicking idioms of a sequential language? Send a message for what you want and get the custom reply based on that. It's about the result of each function, not the function itself, after all. (Plus there's the flexibility and scalability of message passing, etc.)
Although processes aren't totally free compared to calling from a library module, Erlang-level processes are dirt cheap (especially if the message communication is within the same node). They're not OS-level processes. The overhead would be comparable (or better) to dynamic function calls and object instantiation in heavier scripting languages.

Resources