Ookma-Kyi

Ookma-Kyi

Using a struct within a struct produces errors

I have the following code:

defmodule Servy.Conv do
  defstruct method: "", path: "", resp_body: "", status: nil

  def full_status(conv) do
    "#{conv.status} #{status_reason(conv.status)}"
  end

  defp status_reason(code) do
    %{
      200 => "OK",
      201 => "Created",
      401 => "Unauthorized",
      403 => "Forbidden",
      404 => "Not Found",
      500 => "Internal Server Error"
    }[code]
  end
end

I get a “could not find struct” error when I update the full_status function to def full_status(%Conv = conv) do, even though the struct is defined above. Additionally, Visual Studio Code mentions

Cyclic module usage

When I try to do this. Any ideas?

Most Liked

garrison

garrison

I agree this behavior is confusing; I also think it would be more intuitive to alias the current module into itself. I can’t explain exactly why, it’s just less surprising for some reason.

With that said, obviously there is no changing this now, so it is what it is.

Structs are just maps with an extra __struct__ key set to the module name. Functions are imported into the scope, but structs are not. You can only alias the module name.

Note however that defining a nested module aliases that module within the parent, so you can do this:

defmodule A do
  defmodule B do
    defstruct [:foo, :bar]
  end
  def foo(%B{}), do: true
end

Even though the actual name of B is A.B. Which only makes it more confusing tbh.

gregvaughn

gregvaughn

Yes, but it’s even more fundamental than that. The struct “name” is a module name. Even if you were not creating a struct, but in any module you cannot refer to the current module by the leaf part of its name. For example, if you were writing any function within module Foo.Bar you cannot use Bar by itself. You’d have the same 3 options I mentioned.

sodapopcan

sodapopcan

Just to put what @gregvaughn another way (which is what helped me) is that Elixir doesn’t technically have submodules. The . is a bit of an illusion and is only meaningful for constructs like alias, otherwise it’s just like any other character in a module name. Foo and Foo.Bar have absolutely no relation as far as the VM is concerned.

sodapopcan

sodapopcan

That goes back to what Greg was saying that structs are named after the module itself. This is no different than if you want to use a module within itself: you either have to use __MODULE__ or you can type the full name verbatim.

As I said in my previous answer, Foo.Bar and Foo are completely different modules. It sounds like you are still thinking of it as Bar is a module within Foo. This is not the case, they are totally independent. Just think of . as an underscore. The . between the module name and the function, however, is an operator, though. It’s separating module and function name.

Sorry for the all the edits but I perhaps it’s clearer to say that the Foo in Foo and the Foo in Foo.Bar also have absolutely no relation.

gregvaughn

gregvaughn

The struct’s module is Servy.Conv not Conv. You have a few choices. You could use the full module name, or you could alias or you could use the compile time variable __MODULE__. For example:

def full_status(%__MODULE__{} = conf) do

I prefer the compile time variable because if you ever refactor the module and change its name, this will reflect the current name.

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
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
LegitStack
I’m hoping you guys can give me some general advice and perhaps code examples if you’re feeling up to it. I’m very interested in Elixir,...
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
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
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
Mooodi
Given a string, how can I get access to its character by index? Enum.at("my_string", 2) doesn't work. Or rather, not char, but a substr...
New
wernerlaude
In AR this is so simple @articles = current_user.articles How to do in Ecto? def index(conn, _params) do current_user = conn.assig...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

yurko
Here are few pieces of (common) Linux knowledge that we use for reasonably small one server apps. We use Ubuntu but this should work for ...
New
dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
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
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
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
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
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
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

We're in Beta

About us Mission Statement