7rans
I implemented Access behavior for a struct today. Pseudo-code…
defmodule MyStruct do
defstruct data: %{}
@behaviour Access
# ... implementation of Access behavior on `data` ...
end
Then I tried:
a = %{x: 1, y: 2}
s = %MyStruct{data: a}
z = %MyStruct{ s | y: 3 }
And of course it did not work.
Sure would be awesome if it could be made to work somehow though.
Trending in Proposals: Ideas
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Hi everyone!
The first release candidate for the Expert language server project is now available!
We’ve published a press release detai...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #security











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
zachallaun
You generally shouldn’t need to implement
Access. For instance, in your example, you can already use theput_in/etc. helpers for ergonomic updates:cmo
Why would you want that to work?
7rans
It does seem odd at first glance, I realize. The reason has to do with changesets. I have a function that updates a structure (e.g. some fields are calculations based on other fields). Which is fine, but when working with a web form the data is stored as a changeset. To perform those same updates I either have to re-implement the function for a changeset (using
get_field, etc) or I have to apply the changes, take the resulting structure and run it through my function, and then make a new changeset.So it occurred to me that I could wrap the changeset in an special module using Access behavior and use bracket notation (instead of dot notation) in my original function and then my original function can take a struct or a changeset. Mostly it would work. But it’s not a perfect polymorphism. Some things won’t work like the update shorthand.
This is one area where I think OOP in general, and Ruby in particular, really shines. It’s quite easy there to create an interface wrapper that would allow something like this to work. As it stands in Elixir, I don’t think I have much choice but to implement my function twice, once for the structure and another for the changeset.
D4no0
It is absolutely not clear what you want to do, can you show a extensive example that involves ecto changesets?
Or maybe the problem could be reformulated, it is often the case that you will try to do things the way you were used to in other languages.
7rans
Sure. Here is a very simplified bit of code to demonstrate.
So, when working with LiveView I create a changeset (
Foo.changeset(%Foo{})pass that toto_formand it gets assigned to the socket… standard stuff. When the form on the web page changes, say viadef handle_event("change", %{"foo" => changes}, socket)I use thechangesto get a changeset.Foo.changeset(%Foo{}, changes). Now I need to run it throughcalculateto updatexand send it back to the webpage. Butcalculatetakes a%Foo{}not a changeset of it.So what to do? One way to to write another calculate function that can take a changeset of Foo. Something like…
The downside of course if lack of DRY – I am implementing the same functionality twice.
The alternative is to apply the changeset, call calculate and make a new changeset.
This works, but it applies an update I am not necessarily ready to apply (certainly not to the database) and it seems a rather “long way round” just to get back to an updated changeset.
So anyhow, I hope that clarifies things. My thought was maybe I could wrap that changeset in an Access behavior so I can pass it to the same
calculatefunction that the struct itself uses. That’s where the idea of this thread spawned.(Note I actually was able to implement this Access behavior, at least in part, but as I point out it is an imperfect polymorphism). Here is the code thus far:
LostKobrakai
Why make a new changeset though? You could change the changeset you already have to include the change for your freshly calculated
x.sodapopcan
Why do you need both versions of the function? If
calculateis changing part of%Foo{}that’s exactly what change-sets are for. They should be the sole interface for change of Ecto-backed structs.D4no0
What kind of functionality you are implementing twice? You literally have a function receiving a changeset that adds an additional change.
I really hope this is not a production project, if it is, please stop.
As other mentioned above, a changeset is literally a list of changes you apply to your data. You can achieve what you want easily by:
If you need different behaviors based on where you use the changeset (for example a lot of times you might have forms where full validation doesn’t make sense), you can literally define different functions that will generate and validate your changeset differently.
7rans
Not sure it’s all that bad. I’m just routing the changeset gets and puts I would otherwise use through an Access behavior. But as I said, it’s probably not quite polymorphic enough to really make it worth it.
I actually tried putting
calculatein the changeset function just as you suggest. Seemed like a great idea at the time, but I ran into an issue because in my actual case the calculate function also needs some external “calibration” parameters, which need to be passed in. I considered adding a third parameter tochangeset()but I felt that was mucking up the typical interface for changeset, so it felt off to me. (Maybe I could use a special entry toparamsthough, I didn’t try that.)It still (could) lead to me implementing calculate twice – there shouldn’t be a need to create a changeset if I am just creating the struct programmatically. But I suppose I could create a changeset then too.
Funny thing is I had just started to think I should apply the changes and work with struct directly, but now these comments have me thinking the opposite.
I think that supports my overall point though… It would be nice if we didn’t have to implement it one way or the other – some way to pass in the struct or the changeset and the same code could work on it either way.
D4no0
You are literally trying to design a class like code, that achieves nothing but introduces complexity to the reader without any reason.
Creating the struct programmatically will skip all validation, this defeats the whole propose of using ecto schemas in the first place.
As I mentioned above, changesets are extremely versatile, you can easily write something like this:
If you don’t want the field in the final struct, you can pass it as an argument to the calculate function (however, you lose the benefit of validation if that’s important for you).