I have this code to define encoder for Tuple
defimpl Jason.Encoder, for: Tuple do
def encode(tuple, opts) do
Jason.Encode.list(Tuple.to_list(tuple), opts)
end
end
I tried to migrate to using the new JSON module in elixir 1.18
require Protocol
Protocol.derive(JSON.Encoder, Tuple)
and i get this error
== Compilation error in file lib/shopcash/changes.ex ==
** (ArgumentError) Tuple.__struct__/1 is undefined, cannot expand struct Tuple. Make sure the struct name is correct. If the struct name exists and is correct but it still cannot be found, you likely have cyclic module usage in your code
how can i do the same using this new JSON module?
If we’re talking about the Elixir Tuple
module (Tuple — Elixir v1.18.1), I’m not surprised the new implementation isn’t working… but am surprised your old one is.
Tuple
doesn’t appear to be a struct which is a requirement for both the new JSON.Encoder
and Jason.Encoder
… not surprising since we’re talking about protocols. Maybe I’m missing something in the Tuple
source code or some other sorcery that gets you there… but right now the error looks correct absent further information.
1 Like
The old implementation forces the encoder to treat tuples as list. Wonder if i can do the same with with new JSON module
Yeah, I see what you’re trying to do now and why it likely worked in the old implementation.
I wonder if something like this might work:
defimpl JSON.Encoder, for: Tuple do
def encode(tuple, _encoder) do
JSON.encode_to_iodata!(Tuple.to_list(tuple))
end
end
It’s not exactly the same, but close. Also, I’ve not tried this and I could be completely 100% wrong in what I’m suggesting: as you can probably tell, I’m futzing through this. Finally this is “just try to get it to work” code and not really that good… but it might help resolve the concept.
(I’m mostly engaging on this not so much because I have depth of knowlege on this feature as much as I’ve got a couple places I ought to convert in my own code base and may as well learn it )
I looked into the elixir source code and came up with this
defimpl JSON.Encoder, for: Tuple do
def encode(tuple, encoder) do
:elixir_json.encode_list(Tuple.to_list(tuple), encoder)
end
end
1 Like
I think that’s roughly the same to what I was suggesting.
My only caution to you’re reaching rather deeply into Elixir’s Erlang code to get that function which isn’t part of the public API, but rather part of the implementation details… with the ramifications thereof.
Indeed, from the JSON source code itself (which may well be where you got this):
defimpl JSON.Encoder, for: List do
def encode(value, encoder) do
:elixir_json.encode_list(value, encoder)
end
end
So all your Tuple impl has to do is get it to a list
and the public API of JSON
should have you covered.