slouchpie

slouchpie

Are module attributes "read" multiple times in same function?

Greetings comrades,

According to: https://elixir-lang.org/getting-started/module-attributes.html#as-constants

Every time an attribute is read inside a function, Elixir takes a snapshot of its current value.

My question is:

In this function:

@money %{amount: 0, currency: :DOGE}

def reset_global_debt do
  for human <- Earth.list_humans() do
    update_financial_record_for_human(human, %{
      "total_amount" => @money.amount,
      "base_currency" => @money.currency
    })
  end
end

do 2 copies of @money get created, since it is “read” twice?

I hope not…

Marked As Solved

eksperimental

eksperimental

Here’s the code.
you can clone it GitHub - eksperimental-help/slouchpie

Unoptimized: slouchpie/foo_big.ex at main · eksperimental-help/slouchpie · GitHub

Optimized: slouchpie/foo_small.ex at main · eksperimental-help/slouchpie · GitHub

$ mix compile

$ touch lib/foo_big.ex && rm _build/dev/lib/slouchpie/ebin/Elixir.Foo.Big.beam 
$ time mix compile
Compiling 1 file (.ex)
Compiling lib/foo_big.ex (its taking more than 10s)

real  0m33.185s
user  0m28.222s
sys 0m4.836s

$ touch lib/foo_small.ex && rm _build/dev/lib/slouchpie/ebin/Elixir.Foo.Small.beam 
$ time mix compile
Compiling 1 file (.ex)

real  0m2.502s
user  0m2.306s
sys 0m0.331s

$ ls -alh _build/dev/lib/slouchpie/ebin/Elixir.Foo.*.beam
 23M Dec 15 14:14 _build/dev/lib/slouchpie/ebin/Elixir.Foo.Big.beam
2.1K Dec 15 14:15 _build/dev/lib/slouchpie/ebin/Elixir.Foo.Small.beam

$ elixir --version
Erlang/OTP 24 [erts-12.1.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit]

Elixir 1.13.0 (compiled with Erlang/OTP 24)

UPDATE:

Here are the benchmarks
https://github.com/eksperimental-help/slouchpie/blob/main/benchmarks/foo.exs

Elixir 1.13.0
Erlang 24.1.2

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 5 s
parallel: 1
inputs: none specified
Estimated total run time: 24 s

Benchmarking Unoptimized: Foo.Big...
Benchmarking Optimized: Foo.Small...

Name                           ips        average  deviation         median         99th %
Optimized: Foo.Small      292.62 K        3.42 μs   ±436.00%        2.46 μs        6.48 μs
Unoptimized: Foo.Big       83.26 K       12.01 μs   ±123.18%        7.73 μs       30.17 μs

Comparison: 
Optimized: Foo.Small      292.62 K
Unoptimized: Foo.Big       83.26 K - 3.51x slower +8.59 μs

Memory usage statistics:

Name                    Memory usage
Optimized: Foo.Small         4.53 KB
Unoptimized: Foo.Big         9.09 KB - 2.01x memory usage +4.56 KB

**All measurements for memory usage were the same**

Also Liked

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

It is as if you hand typed that map in two places. This can affect compile times, but it generally requires very large constants to be an issue.

lud

lud

If you are seeing this because of “decompiled” code, keep in mind that this code is built from the debug_info or abstract_code chunks of the beam files. I am not sure those contain all optimizations done by the compiler.

lud

lud

If you can read erlang you can use mix decompile to turn your compiled module into erlang source. And you will see that whenever an @attribute is used, the litteral value is present in the source.

Now if you cannot read erlang I guess you will recocgnize your own data enough to verify too.

slouchpie

slouchpie

Yup I understand now.
At compile-time, every module attribute usage is effectively “written out” in full in the code.
So it’s only a concern for very large constants, or if the attribute is accessed in a compile-time loop (e.g. in macros).
Thanks.

NduatiK

NduatiK

To add onto the previous answer. The cost occurs when you make a change.

The following would be calculated twice. If we were doing expensive or numerous changes, it would affect the time taken to compile

@var1 1+1
@var1 1+2

Where Next?

Popular in Questions Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
dokuzbir
Hello, I am trying to convert my lists to string without losing brackets.For start i have 3 map. They look like these buyer = %{ id: ...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

Other popular topics Top

peerreynders
Manning 2016 Halloween weekend sale via Deal of the Day Friday, October 28 - Half off all MEAPs - code WM102816LT Saturday, October 29 ...
326 29600 154
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 42633 214
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

We're in Beta

About us Mission Statement