mjlorenzo
Hi folks, got a question about how Elixir determines when to recompile a module. The documentation says a module will recompile when one of its dependencies changes, but that doesn’t seem to be the case here and I’m not sure why. Here’s the scenario:
I have a module that defines a schema for the library I’m building:
defmodule Schema do
import Library.Schema.Notation
schema :name do
# macros and schema definition...
end
end
When this compiles, it exposes a callback __schema__ to be consumed in another module. While Library.Client actually consumes the schema, Testbed is the intended product module:
defmodule Testbed do
use Library.Client, schema: Schema
#. (Library.Client.__using__() actually calls Schema.__schema__())
# ... callbacks and implementation
end
I figured because Testbed references Schema, then it should know to recompile if Schema recompiles. I’m consistently seeing however that changes made to Schema do cause itself to recompile, but Testbed still doesn’t and I have to manually recompile it to reflect the changes in Schema. This ring a bell for anyone?
Thanks,
Mike
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
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #ai
- #phoenix_html
- #elixirconf-us
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
sodapopcan
With an oversimplified mix project, I am unable to reproduce this:
and when I change
Schema:Could you possibly share more code and your Elixir version? Is this in a mix project?
awerment
I’m able to reproduce it with a
__schema__()function (not macro) and without therequire unquote(schema).Think the issue might be with the fact that
schemainunquote(schema).__schema__()is dynamic and there is no hard dependency on the module, in might be loaded at runtime after all. AddingCode.ensure_compiled!(unquote(schema))inside the quote block indefmacro __using__(..)works for me.sodapopcan
My first attempt was with a non-macro
__schema__()and no require and still couldn’t reproduce. I just changed to a macro to more closely fit what I imagine the real code is.sodapopcan
Ah ya, in your example simply doing
unquote(schema)isn’t going to do anything anything meaningful if you’re just using a regular function in the way you have it. You’d need to doimport unquote(schema)for__schema__to be available inTestbed.awerment
Yeah, I’m guessing the call to
__schema__()is itself inside a function definition within the macro’s quote block? If it’s called outside as in your example, it works for me, too.sodapopcan
It’s just that saying
unquote(schema)on its own is going to expand to justSchemawhich is simply the atomSchemawhich is a no op. If you doimport unquote(schema)that will actually import its functions. You don’t needensure_compiledthere asimportensures its compilation.awerment
That’s true, I assumed @mjlorenzo’s
Library.Clientmodule would look something like this:In that case, without
Code.ensure_compiled!,Testbedis not recompiled whenSchemachanges.sodapopcan
Yes, that is correct behaviour in this situation because it’s inside a function which makes it a runtime dependency.
mjlorenzo
@sodapopcan, @awerment thanks y’all for the discussion. This is the top of
Library.Client.__using__:If i’m understanding correctly, because the above is entirely in the macro body of
Library.Client.__using__,Testbeditself has no idea to interpretSchemaas anything other than the atom and so no dependency exists. Injecting some sort ofimport,require, etc intoTestbedwill establish this. On the right track?sodapopcan
Mostly, yes. Nothing outside of the returned quoted expression will be injected into
Testbedso once that module is compiled, all that stuff is gone. So in this case it’s not that it isn’t interpretingSchemaas anything other than the atom it’s thatSchemaisn’t even present in the compiled code! Again it’s hard to see without more context but there doesn’t seem to be anything about that code snippet that suggests you needMacro.expandoverrequireing orimporting within a quote block which of course you want anyway to create the dependency. It depends what you’re trying to accomplish, of course.I’ve also never actually seen
ensure_compiled!used inside a module before. I’m not a master of macros, though, so maybe there is a good reason, but AFAIK,ensure_compiled!is essentiallyrequirefor use outside of adefmodule. Don’t quote me on that, though