rschooley

rschooley

This works, but I’d like to clean it up a bit (extra functions in caller):

defmodule whatever do
  defp do_thing(%{source: "foo"}) do
    IO.puts("calling foo")
  end

  defp do_thing(%{source: "bar"}) do
    IO.puts("calling bar")
  end

  def handle_info(:dont_care, state) do
    SomeContext.some_query
    |> Enum.each(fun record ->
      {:ok, yeah} = do_thing(record)
    end)
  end
end

But moving the extra private functions into their actual modules results in this error:
function do_thing/1 imported from both Bar and Foo, call is ambiguous

defmodule Foo do
  def do_thing(%{source: "foo"}) do
    IO.puts("calling foo")
  end
end

defmodule Bar do
  def do_thing(%{source: "bar"}) do
    IO.puts("calling bar")
  end
end

defmodule whatever do
  import Foo, only: [do_thing: 1]
  import Bar, only: [do_thing: 1]
  ....
end

I looked at protocols but didn’t see how they could clean this up. I’d like to just call a modules’ do_thing method without having a wrapper method for each one. Is there a way to do this? Thanks.

Showing Posts 1 to 6

BrightEyesDavid

BrightEyesDavid

I think you can simply include the module when calling the function with Foo.do_thing(), and that importing or aliasing a module is “just” a way to avoid having to use the module name for every call.

Edit: see here and here for fuller and more accurate information.

rschooley

rschooley OP

Hi @BrightEyesDavid,

Explicitly calling Foo. is what I am trying to avoid.

To call Foo. I’d have to match on source in a case statement, or pattern match in the do_thing function args (1 for each source type).

I am doing the latter above, but am wondering if there is a way to just call either modules function directly based on the pattern in the struct.

To summarize, it looks like two functions can have the same arity and arg types

  • if they match on a different value in the struct arg
  • and are defined in the same module

but

  • that doesn’t work if the function are defined in different modules and then imported

Edit: to give an example of what I have now, and it’s ok and works, but might be improved is this:

defp do_thing(%{source: "foo"} = record), do: Foo.do_thing(record)
BrightEyesDavid

BrightEyesDavid

Ah, sorry. :slight_smile: I did wonder if I was missing something.

hugolnx

hugolnx

Hi, @rschooley! That’s a pretty abstract question/sample hehe

But, if your do_thing is a call that make a thing so different with each kind of record, I would guess that it structure changes a lot depending on its source. If is that the case, I think it make sense that each type of record is a struct and that exist a ThingDoer protocol, so you could easily extend this thing to be done to other record types in the future. It would be something like that:

defmodule FooRecord do
  defstruct [:content, source: "foo"]
end

defmodule BarRecord do
  defstruct [:content, source: "bar"]
end

defprotocol ThingDoer do
  def do_thing(record)
end

defimpl ThingDoer, for: FooRecord do
  def do_thing(record), do: IO.puts("calling foo")
end

defimpl ThingDoer, for: BarRecord do
  def do_thing(record), do: IO.puts("calling bar")
end

defmodule ThingDoerBoss do
  def handle_info(:get_thing_doers_to_work, state) do
    [
      %FooRecord{content: "lol"},
      %BarRecord{content: "xpto"},
    ]
    |> Enum.each(&ThingDoer.do_thing/1)
  end
end

With that solution you can easily extend the do_thing to other source structures and also have the record structures documented.

PS.: In that case, your SomeContext.some_query must return the records as structs.

PS2.: I would not recommend you to use this import overriding thing even if it worked, it seems that would be a hell of situation to navigate through modules trying to discover in which of them are the matching function hehe

rvirding

rvirding

Creator of Erlang

To clarify things a bit. In module Whatever you are only defining one function do_thing/1 which has two clauses. While it looks 2 separate functions they are actually parts of the same function. In the modules Foo and Bar you are defining 2 different functions do_thing/1 so now you have 3 functions do_thing/1 in separate modules. What uniquely defines a function is the module its in, its name, and its arity (number of arguments). Importing does not change that, it just gives you a way of not having to prefix calling a function in another module with the module name. You still have 3 different do_thing/1 in 3 modules.

rschooley

rschooley OP

Interesting… thanks for this!

— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
water
I’m aware of 2 such projects, are there others? git: GitHub - team-alembic/realworld: A fullstack Phoenix LiveView application with back...
New
itzmidinesh
Hi all, I’m working on a Phoenix project where I need to make external HTTP requests and I’m trying to choose between Req and HTTPoison....
New
peck
Hi everyone. My team and I have been working on a fairly modest app based around video streaming and chat, but we’ve landed a customer t...
New
leoschweizer
Hi, we run different LLM models across a cluster, with each node loading a configurable subset. Model-specific queues let nodes consume ...
New
csmr
Hi all, I’m new here and would like to hear peoples views on my Elixir/Phoenix based game-engine! :smiley: Mutonex gamedesign was finish...
New
Stef-Verniers
Hello I’ve been coding in Elixir for almost two years now because of my current job where we implemented Elixir in our application. But ...
New

Other Trending Topics Top

dominicletz
Hey there, I haven’t seen a list of useful Elixir specific skills for the popular AI tools yet so I’m starting one here with my first. ...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews