fireproofsocks
This is a code style question (mostly?). I’m using use and the __using__ macro to share private functions between other modules. The functions have the same name and arity: the idea is that they get called recursively to validate input and accumulate errors. This works well, EXCEPT for one thing that looks… smelly: Because of how matching works, the most specific function clauses are declared first, and then the most general catch-alls appear last. What this means is that my modules have to put the use clauses BELOW, like this:
defmodule MyThing do
defp foo(%{very: "specific", match: "clause"} = args, acc) do
# implementation... then call the "shared" functions
foo(args, acc)
end
use FunctionsInSharedModule # <--- down here!
end
My question is: is this bad form? Some style guides stat that use statements should appear near the top of the module declaration, and it’s easy to miss a use tossed into the bottom of the module. Am I being too sensitive? I’m trying to think of a more elegant way to structure this.
Your thoughts are welcome!
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex











First 5 of 5 Posts
benwilson512
I believe you can replace injecting the code with this:
Then
CommonValidations.foogets to be a proper function instead of an injected one, with all the benefits of better error messaging.fireproofsocks
That assumes that
CommonValidations.foois a public function, yes?My use case is slightly more complex (I tried to keep things simple): I’m actually
useing multiple modules to compose the set of functions/rules that make sense for each use case, so I have to think through how that might be affected…benwilson512
Function calls are the easiest way to compose functions. If you want to indicate that a module or its functions are internal that’s what
@doc falseor@moduledoc falseis great for that. Macros, and injecting functions with macros, have a place, but that’s generally when something about those functions would make them difficult or problematic to call directly. Really though this should be a last resort, and I think it is far more likely of a need in something like a library than in your application code.If you are finding yourself needing
usebecause you want to call other private functions then you need to take a seriously look at your module and figure out if you are treating it like a class.If you still want to have some stuff in your common functions call functions within the specific module, use a behaviour, and pass the module name in to your common eg:
gregvaughn
While I agree with what Ben is saying – this may not be a good use of macros. If it is though, it is not a good use of
usewhich is syntax sugar over require and direct macro call and is expected at the top of the file. However, if you made that a more explicit macro call, it would reduce the “smell”.For example, replace:
with something like:
and the necessary
require FunctionsInSharedModuleat the top of the fileal2o3cr
A more idiomatic way to get the intended behavior (“add these clauses to the end of the module that called
use FunctionsInSharedModule”) is the@before_compilecallback. For instance, it’s used to declare a catchallrenderfunction inPhoenix.View