Following on from the Do you make use of term_to_binary? thread, do you know of any other lesser known tips or tricks you think others might be interested in?
If so please share!
Following on from the Do you make use of term_to_binary? thread, do you know of any other lesser known tips or tricks you think others might be interested in?
If so please share!
There’s a compact way to do a one-line conditional (ab)using list comprehensions:
[do_thing() || BooleanValue, check_stuff()]
It works because you can have both list generators and filters, but the generators are optional.
It even works with conditions not allowed in guards. But be aware of readability concerns
Oh, here’s another one: there’s a built-in function in the shell—rp(Term)
—that pretty-prints terms to infinite depth. That way you don’t have to type io:format(“~p~n”, [Term])
all the time!
If you want to learn more about this, you can check the article(s) I wrote a while back…
As a matter of fact, the whole Erlang Battleground blog is full of articles that would be proper responses to the topic of this thread.
In Erlang/OTP 26, we have documented some previously undocumented details about list comprehensions, including what happens when filters fail:
(to be included in the second release candidate, which will be released this week)
The right-hand operands of andalso
and orelse
can be any term, it doesn’t have to be true
or false
.
As a (contrived) example, if maps:get/3
didn’t exist, it could be written like this:
maps_get_with_default(Key, Map, Default) ->
case maps:is_key(Key, Map) andalso {value, maps:get(Key, Map)} of
false -> Default;
{value, Value} -> Value
end.
I got the feeling that I’ll be doing this a lot in this thread. When you folks get tired of this, let me know…
But… I also wrote an article about that semantically questionable technique…
I was a bit reluctant to share this “trick”, TBH, and I’m definitely not encouraging it
Maybe all posts in this thread should flash a warning like “Don’t do this at home!”
Those lesser know tricks are lesser known not so much because they are secret magic but because they are dirty tricks
IMHO:
andalso
and orelse
” is not a trick.bc(B) when byte_size(B) > 64 -> binary:copy(B);
bc(B) -> B.
I use this to store values is process state when such values are received from an external large BLOB (like a JSON) after jsone:decode/1.
I like to write it that way, Mainly to avoid multiple case
I also defined some macros
Blockquote
-define(IF(IFTure, DoThat), (IFTure) andalso (DoThat)).
-define(IIF(Cond, Then, That), case Cond of true → Then; _ → That end).
-define(IIF(Expr, Expect, Then, ExprRet, That), case Expr of Expect → Then; ExprRet → That end).
this is just to make the code look like it’s on one line
That is why I put “trick” in quotes
Using ets:match_spec_run/2
over lists for dynamic filtering at runtime.
Meant I could avoid erl_parse
/erl_eval
/runtime-module-compilation.
I vaguely remember it being ‘fast enough’ for a small-time advertising auction hot path when I last used it (5+ years ago), no idea if it still is the best option. The need here was to take the request, turn it into a match_spec
and run it over targeting rules.
On a related note, merl
was helpful for my RADIUS encoder/decoder. I parsed the dictionaries and emitted code directly…in a similar vain to using ASN.1 but for RADIUS.
(Disclaimer: This is not a trick and definitely not a tip. Do this only at home, not in public )
A while ago, @juhlig told me about a presentation from a conference he attended, where somebody created a fun project for an obfuscation library that turns Clojure code into Morse code which is still valid Clojure code, and I was like “Haha, yeah, whatever serves to waste your time ”.
But just lately, I realized what fun stuff you can do, also in Erlang.
The below is valid, working Erlang code (sane versions in comments):
-module(hugger).
-export(['🤗'/1]).
% -export([hug/1]).
'🤗'('😢') -> '🙁';
% hug(crying_person) -> sad_person;
'🤗'('🙁') -> '😐';
% hug(sad_person) -> ok_person;
'🤗'('😐') -> '🙂';
% hug(ok_person) -> happy_person;
'🤗'(Other) -> Other.
% hug(Other) -> Other.
(The module name must not contain non-latin1 characters though, so we can’t go all the way and use Emojis there. Bummer… )
Trying it out in the shell:
1> hugger:'🤗'('😢').
'🙁'
2> hugger:'🤗'('🙁').
'😐'
3> hugger:'🤗'('😐').
'🙂'
4> hugger:'🤗'('🌳').
'🌳'
5> lists:map(fun hugger:'🤗'/1, ['😢', '🙁', '😐', '🙂', '🌳']).
['🙁','😐','🙂','🙂','🌳']
You. Are. Evil.
Much as I like you, the day I see something like this used, I swear I’ll sue you for putting crazy ideas in peoples heads
That said, this was the presentation I attended, last year at ClojureD/ClojureU: :clojureU 2022: "Use of Macros Leads to Remorse" by Paula Gearon - YouTube
Something like this can be done out of the box in Clojure as well btw:
user=> (defn 🤗
[x]
(case x
:😢 :🙁,
:🙁 :😐,
:😐 :🙂,
x))
#'user/🤗
user=> (🤗 :😢)
:🙁
user=> (map 🤗 [:😢 :🙁 :😐 :🙂 :🌳])
(:🙁 :😐 :🙂 :🙂 :🌳)
Sometimes i find block expressions useful especially with list comprehensions
[ begin
do_something(X),
do_something_else(X),
...
end || X <- ...]
This sounds somewhat familiar to me… I wonder why that may be?
You can implement a rather efficient single-shot “pub/sub” via monitors, and pass data in a ‘DOWN’ messages:
In this vain, plenty of tricks in:
One of the really interesting tricks to come of it was to raise the process priority of the dispatcher.