OmanF

OmanF

Structs aren't enforced

In the attached screenshot (taken from an exercise in “Programming Elixir”) can be shown that BugReport is defined as a struct that, itself, has as a value for one of its keys a struct: Customer.

Yet, when I tried, in iex, both the put_in function and its expanded form, when the owner key received a single string, succeeded.

My understanding of structs is that once I defined BugReport to take a Customer as the type of the key owner, it set in stone.

So, what am I misunderstanding about defining structs?

Thanks.

Most Liked

peerreynders

peerreynders

defmodule BugReport do
  defstruct owner: %Customer{}, details: "", severity: 1
end

defstruct takes a keyword list. The keys describe the keys for the struct the values are the default values when the struct is created. The type of a value under a key isn’t fixed (Elixir is dynamically typed). Required keys are identified with the @enforce_keys module attribute.

You can use @type to indicate what the type should be for use with dialyzer. See this and this for the limitations of success typing.

michalmuskala

michalmuskala

Why should it fail? Elixir is a dynamically typed language - there are generally no type constraints. The values in struct declaration are about a default value when a new struct is created - they don’t mean anything more and in particular don’t affect how struct can be updated.

dimitarvp

dimitarvp

As others mentioned, Elixir is dynamically-typed.

However, you can define the structures as Ecto schemata and enforce types via the Changeset functions – even without using a database (many people wrongly assume using Ecto mandates a database). This thread has pointers on how to use Ecto without a database – maybe even better resources exist.

You can even use plain structures without Ecto wiring, as long as you pass in typing information when assigning struct fields.

Have in mind though, if you are gonna use Ecto’s Changeset, that should be the only way you manipulate the structures defined through it. No normal assigments or Access functions should be used (like put_in in your code).

IvanR

IvanR

Elixir is dynamically-typed. However, with a library like Domo, it’s possible to validate struct’s type explicitly as the following:

defmodule Customer do
  use Domo
  defstruct name: "", company: ""
  @type t :: %__MODULE__{name: String.t(), company: String.t()}
end

defmodule BugReport do
  use Domo
  defstruct owner: %Customer{}, details: "", severity: 1
  @type t :: %__MODULE__{owner: Customer.t(), details: String.t(), severity: non_neg_integer()}
end
bug_report = BugReport.new!(owner: Customer.new!(name: "OFK", company: "PragProg"), details: "It's Broke!", severity: 1)
%BugReport{
  details: "It's Broke!",
  owner: %Customer{company: "PragProg", name: "OFK"},
  severity: 1
}

bug_report.owner |> put_in("This should fail, right?") |> BugReport.ensure_type()
{:error,
 [
   owner: "Invalid value \"This should fail, right?\" for field :owner of %BugReport{}. \
Expected the value matching the %Customer{} type."
 ]}

%BugReport{bug_report | owner: "How about this?"} |> BugReport.ensure_type()
{:error,
 [
   owner: "Invalid value \"How about this?\" for field :owner of %BugReport{}. \
Expected the value matching the %Customer{} type."
 ]}

%BugReport{bug_report | details: "Updated details"} |> BugReport.ensure_type()
{:ok,
 %BugReport{
   details: "Updated details",
   owner: %Customer{company: "PragProg", name: "OFK"},
   severity: 1
 }}

Where Next?

Popular in Chat/Questions Top

nur
https://e.planaria.network/stack.png https://e.planaria.network Build a NoSQL DB, Build a Relational SQL Database, Build a Graph Datab...
New
wolfiton
Hi everyone, How can i retrieve the name from a structure like this? %{"id" => "1570", "name" => "Croque Monsieur"} My test loo...
New
Fl4m3Ph03n1x
I am doing some exercises while learning Elixir using Exercism.io. Now, my objective is to do all exercises, extras included. This shoul...
New
LegitStack
I’m not a hugely experienced programmer, just a few years. So I’m looking for resources to learn about a topic but I can’t seem to find m...
New
New
wallyfoo
Long story short, I have a real world need to create a view for hooking up a shipping terminal to live data, but because of some early ar...
New
marciol
Hey, I have very restricted resources and time so I’m trying to understand the best way to learn Liveview in terms of cost/time. The Pra...
New
AstonJ
It finally feels like I’ve got some time to catch up on my reading - though I am sure lots of people will be wondering the same: what are...
New
SavagePixie
I was wondering if there are any beginner-friendly, exercise-based resources for learning Elixir out there. I’m looking for something lik...
New
shansiddiqui94
Greetings Elixir Developers, My name is Daniel, and I am taking my first step to learn all about the Elixir language. Currently I have a...
New

Other popular topics Top

sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
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
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
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
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
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
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

We're in Beta

About us Mission Statement