Sebb
Struct without fields
I just tried to create a struct without fields (because: why not?).
It’s not possible with defstruct, which insists on an argument.
Best it can do is
defstruct _: nil # nice
btw, this is not OK:
defstruct [_]
isn’t that inconsistent?
So I tried to figure out what defstruct does. From the docs:
To define a struct, a developer must define both
__struct__/0and__struct__/1functions.defstruct/1is a convenience macro which defines such functions with some conveniences.
Where are __struct__/x documented?
Structs are usually defined with the
Kernel.defstruct/1macro
What if I want to be unusual? How can I define a struct by hand, maybe even without fields?
Marked As Solved
NobbZ
Using an empty list as argument to defstruct/1works for me:
iex(1)> defmodule S do
...(1)> defstruct []
...(1)> end
iex(2)> %S{}
%S{}
Also Liked
aiwaiwa
One legitimate reason would be to implement a protocol without data.
Use case: postgrex/parameters.ex at v0.16.5 · elixir-ecto/postgrex · GitHub
dimitarvp
…but what’s your goal?
sheharyarn
Like @Nobbz said, you can just do this:
defmodule X, do: defstruct []
The reason this doesn’t work is that you cannot assign _. The first example works because :_ is not _, so you can do defstruct [:_] which is equivalent to your first example.
This is the macro that’s called underneath when defining a new struct. Going over the definition should help you better understand manually defining a struct in a module.
daskycodes
One way to define a struct is to use a simple map with the __struct__ key
Let’s say we have a module StructWithoutFields
we could call
iex> %{__struct__: StructWithoutFields} |> is_struct()
true
This will be a struct but we won’t be able to call %StructWithoutFields{}
The next step I’d suggest is looking into the macro implementation like @sheharyarn suggested.
I left a lot of parts out in the following example but this might give you an idea
defmodule StructWithoutFields do
@struct %{__struct__: __MODULE__}
def __struct__(kv) do
Enum.reduce(kv, @struct, fn {key, val}, map ->
Map.replace!(map, key, val)
end)
end
def __struct__() do
@struct
end
end
With that module you will already be able to call
iex> %StructWithoutFields{} |> is_struct()
true
If you haven’t read it yet I can really recommend reading Metaprogramming Elixir: Write Less Code, Get More Done (and Have Fun!) by Chris McCord
It goes into a lot of detail on how macros work and how basically a lot of elixir is build upon macros
Sebb
thanks for the great advice, can’t fully understand the defstruct-macro yet, but I’ll take a look at the book. (feeling a little too stupid for that right now, not having thought about defstruct []).







