Elixir structs

I would like to define a number of structs in a module. From what I have read, structs defined with defstruct seems to define a struct that takes the name of the enclosing module. Is there another way to do this?

1 Like

There is no other way to define structs in Elixir.

The Kernel.defstruct macro automatically uses the calling module’s name and only allows for one struct per module:

One alternative to structs (though less common in Elixir) would be Erlang’s Records which are available in Elixir through the Record module. This also allows you to create multiple different record types per module. You can learn more about records in the documentation of the Record module.

2 Likes

You can do something like this:

defmodule Foo do
  defmodule Bar do
    defstruct ...
  end

  defmodule Baz do
    defstruct ...
  end
end
7 Likes

Thanks! I’ll look into it.

Thanks! I’ll take a look.

If you’re willing to change your struct syntax slightly you could use my TypeStruct package.

Usage is as follows:

defmodule Foo do
  use TypeStruct

  defstruct User,
            id: integer,
            name: String.t \\ "",
            eye_color: :black | :blue | :brown | :green

  defstruct Group,
            id: integer,
            name: String.t,
            users: [User.t] \\ []
end

After the key comes the type for the field. Default values can be specified with \\ <default value> (Above, the struct Foo.User defines a field :name with a default value of "", and the struct Foo.Group defines a field :users with a default value of [].) Note that fields without a default value are required when creating a struct (in vanilla Elixir they default to nil instead), so if you want a field to default to nil you must explicitly declare field: String.t | nil \\ nil.

Types for the structs are automatically defined (that’s the whole point of the library). The default type is a normal type t. You can set the type with the syntax defstruct Foo, opaque(bar), x: integer. (I am considering changing the default type to opaque.)

(There’s unfortunately no documentation for the library, but that should be all you need for your purpose. I’ve been meaning to document the library for a while.)

Alternatively, you could define your own macro for defining nested structs:

defmodule NestedStruct do
  defmacro defstruct(alias, fields) do
    quote do
      defmodule unquote(alias), do: defstruct unquote(fields)
    end
  end
end

defmodule Foo do
  import NestedStruct

  defstruct Bar,
            a: nil,
            b: nil
end
4 Likes

Hey, this looks great! I will try it out. Thanks for the post!!

1 Like

Ooo that looks quite nice. Is it still possible to use it in an enclosing module to put functions on it, or does it have its own do/end block for adding functions?

1 Like

Yes, you can use it without defining a new module!

defmodule User do
  use TypeStruct

  defstruct id: integer,
            name: String.t
end
2 Likes

OK! This is looking very good!!

1 Like

For anyone stumbling on this thread, have a look at the typedstruct package instead of TypeStruct.

2 Likes