Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duplicate protocol implementations in dependent projects

I have problems with consolidation of protocol implementation in my Elixir project. To be more specific I use Ecto and some simple project called Gold (doesn't matter much atm). The problem is, both of them (Ecto and Gold) use Poison to serialize Decimals (and implement proper Protocol).

Implementation for Ecto looks somewhat like this:

defimpl Poison.Encoder, for: Decimal do
    def encode(decimal, _opts), do: <<?", Decimal.to_string(decimal)::binary, ?">>
end

During development there is a warning saying that the module is duplicated:

warning: redefining module Poison.Encoder.Decimal (current version loaded from /(...)/_build/dev/lib/gold/ebin/Elixir.Poison.Encoder.Decimal.beam)
  lib/ecto/poison.ex:2

But when I try to use for instance exrm to build a release, then I get errors saying that I have duplicate_modules

===> Provider (release) failed with: {error,
                     {rlx_prv_assembler,
                      {release_script_generation_error,
                       systools_make,
                       {duplicate_modules,
                        [{{'Elixir.Poison.Encoder.Decimal',
                           gold,
                           "/(...)/rel/bitcoin_api/lib/gold-0.12.0/ebin"},
                          {'Elixir.Poison.Encoder.Decimal',
                           ecto,
                           "/(...)/rel/bitcoin_api/lib/ecto-2.0.2/ebin"}}]}}}}

How should I deal with this? The case here is I actually use my own version of Gold, so I can tamper with it to fix it asap. I know I can just add Ecto to Gold as a dependency, but that seems a bit overkill to just implement one Protocol like this. Isn't there some kind of a macro to check if a module has already been implemented?

like image 306
Kelu Thatsall Avatar asked Jul 05 '16 21:07

Kelu Thatsall


1 Answers

A quick fix could be to wrap Gold's implementation in a Code.ensure_loaded?/1

unless Code.ensure_loaded?(Ecto) do
  defimpl Poison.Encoder, for: Decimal do
    def encode(decimal, _opts), do: <<?", Decimal.to_string(decimal)::binary, ?">>
  end
end

Its a little icky but then you don't have to add Ecto, but just check if something else already pulled it in

like image 156
sdc Avatar answered Oct 20 '22 01:10

sdc