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
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
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
Yeah, you always want to test performance related stuff on modules not ad hoc evaluated code.
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.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








