japplegame

japplegame

Struct instances do not share the key tuple

It appears that structures created with the %Struct{...} syntax do not share the key tuple.

Compare:

iex> Enum.map(1..1000, &%URI{port: &1}) |> :erts_debug.size()
24000
iex(68)> Enum.map(1..1000, &struct!(URI, port: &1)) |> :erts_debug.size()
14010

The difference in memory usage seems significant. Is it a flaw or by design?

Marked As Solved

Sorc96

Sorc96

That makes sense for performance. I also just tried putting the original code into a module and now both examples have the exact same result. So this must be related to IEx and doesn’t make a difference in regular modules.

Also Liked

al2o3cr

al2o3cr

The %URL{} version expands the struct definition at compile-time. You can demonstrate this with the @compile :S flag:

defmodule Foo do
  defstruct [:bar, :baz, huh: 69]
end

defmodule Bar do
  @compile :S

  def literal_version(x) do
    %Foo{bar: x, baz: 42}
  end

  def struct_version(x) do
    struct(Foo, bar: x, baz: 42)
  end
end

Running elixir on this file fails, but also produces a new file with the extension .S that has BEAM assembly in it.

literal_version compiles to an explicit map operation:

{function, literal_version, 1, 11}.
  {label,10}.
    {line,[{location,"struct_demo.ex",8}]}.
    {func_info,{atom,'Elixir.Bar'},{atom,literal_version},1}.
  {label,11}.
    {put_map_assoc,{f,0},
                   {literal,#{}},
                   {x,0},
                   1,
                   {list,[{atom,'__struct__'},
                          {atom,'Elixir.Foo'},
                          {atom,bar},
                          {x,0},
                          {atom,baz},
                          {integer,42},
                          {atom,huh},
                          {integer,69}]}}.
    return.

Versus the struct version:

{function, struct_version, 1, 13}.
  {label,12}.
    {line,[{location,"struct_demo.ex",12}]}.
    {func_info,{atom,'Elixir.Bar'},{atom,struct_version},1}.
  {label,13}.
    {test_heap,5,1}.
    {put_tuple2,{x,0},{list,[{atom,bar},{x,0}]}}.
    {put_list,{x,0},{literal,[{baz,42}]},{x,1}}.
    {move,{atom,'Elixir.Foo'},{x,0}}.
    {line,[{location,"struct_demo.ex",13}]}.
    {call_ext_only,2,{extfunc,'Elixir.Kernel',struct,2}}.
LostKobrakai

LostKobrakai

Yeah, you always want to test performance related stuff on modules not ad hoc evaluated code.

Sorc96

Sorc96

That’s interesting. I thought %Struct{...} would just call Struct.__struct__(...), but it must be doing something else as well. Since it is special syntax, I’m not sure where to look for the implementation in the Elixir source code.

Where Next?

Popular in Questions Top

gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
Kagamiiiii
Student & New to elixir. Nice language. I want to convert a english character, e.g. “a”, which is stored in a variable, to it’s asci...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
Exadra37
Sometimes I want to check if the input into a function is not a blank string. My first approach: defmodule Example do def do_stuff(s...
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
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New

Other popular topics Top

shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
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
sergio
I couldn’t find any guides that worked well with Phoenix 1.6.0 and esbuild. I hope this helps people test the waters and eases you into t...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
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
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New

We're in Beta

About us Mission Statement