Ok, but as far as I remember, @after_verify can be used for validations but not for triggering recompilation of caller modules. Does the compiler validate the result of that callback? I tried to return different values than :ok but it does not seem to make any difference.
On Friday, September 16, 2022 at 10:43:35 AM UTC-3 José Valim wrote: > Yes, the functionality you ask is the @after_verify callback in Elixir > v1.14. It is used by LiveView to provide functionality similar to Surface > and also the new Phoenix.VerifiedRoutes. :) > > On Fri, Sep 16, 2022 at 14:43 Marlus Saraiva <[email protected]> wrote: > >> Hi Zach! >> >> The only way you can minimize the transitive dependency problem is by >> removing the compile-time deps. I struggled with this for years with >> Surface, and as you did, I tried the approach of removing the runtime deps >> to avoid them from turning into transitive compile-time deps. Eventually, I >> realized that avoiding compile-time deps would be the only way to have a >> permanent solution and started removing any implementation that required >> information at compile-time. As soon as LV v0.8 is out, we'll wrap up that >> work, so we don't expect further issues after that. In the meantime, to >> solve the problem, I added a fix that drastically cut down those >> dependencies, which was to convert the `compile` deps into `export` deps, >> by using `import` instead of `require`. For this to work properly, I have >> to generate and automatically rename a signature function to force the >> recompilation of direct callers whenever the component's metadata (props, >> slots, etc) changes. Otherwise, it would only recompile them if you added >> or removed another function. >> >> It seems to me that Elixir could provide a way to hook into the compiler >> allowing DSL developers to inform a criteria that could be used to trigger >> callers' recompilation. Similar to `__mix_recompile__?`. Maybe something >> like `__export_changed__?` or anything else. With this approach, DSL >> authors could replace the `compile` deps with `export` deps as long as the >> changes in that dependency don't need to be propagated to other modules >> other than the callers. This is the case for Surface and many other libs, >> like Commanded, for instance. I'm not sure the proposed solution would >> solve your issue with Ash but I thought it was worth bringing it here since >> it may solve issues on other libs. >> >> José, is something like that feasible? >> >> >> >> On Tuesday, September 13, 2022 at 8:37:24 PM UTC-3 [email protected] >> wrote: >> >>> Well, its runtime dependencies that create transitive compile time >>> dependencies, isn't it? So if I have a function like >>> >>> defmodule Foo do >>> # callers are aware that they can't use the module at compile time >>> def returns_a_module() do >>> SomeSpecificModule >>> end >>> >>> def something_used_at_compile_time() do >>> 10 >>> end >>> end >>> >>> # and then some other module >>> >>> defmodule Bar do >>> @something Foo.something_used_at_compile_time() >>> end >>> >>> This induces a transitive compile time dependency from Bar to >>> SomeSpecificModule. >>> >>> In the case of Ash DSLs, for example, this happens because we store the >>> resulting configuration in a module attribute. Users are aware that you >>> can't call these pluggable modules at compile time. Only the framework code >>> calls those modules. The above example is contrived, of course, I'm not >>> suggesting that we need a feature to make *that* work, just trying to draw >>> some kind of parallel. >>> >>> I don't see a reasonable way to handle this without essentially removing >>> the ability to use modules in the way that we are. It would be a pretty >>> unreasonable amount of work/change for users to change the way that we plug >>> behavior in Ash. >>> >>> To me, another kind of module dependency, like `runtime-only`, would >>> solve for this, and it would have to be explicitly requested, i.e >>> `expand_literal(.., runtime_only: true)`. Then when determining transitive >>> compile time dependencies, the compiler would not use those modules. >>> >>> >>> On Tue, Sep 13, 2022 at 6:51 PM, José Valim <[email protected]> wrote: >>> >>>> As I mentioned, the issue on transitive compile-time dependencies are >>>> the compile-time deps, not the runtime ones. So I would focus on how to >>>> eliminate those. Otherwise I am not sure we will agree on the problem >>>> statement. :) >>>> >>>> On Wed, Sep 14, 2022 at 12:49 AM Zach Daniel <[email protected]> >>>> wrote: >>>> >>> Although the solution I originally proposed may not be correct (totally >>>>> fine with me [image: 😃]), I think the problem statement is still >>>>> valid. Can we agree that there are some cases where you may want to >>>>> reference a module without creating transitive compile time dependencies, >>>>> i.e in the case of a DSL like what Ash provides? >>>>> >>>>> >>>>> On Sun, Sep 11, 2022 at 3:08 PM, Zach Daniel <[email protected]> >>>>> wrote: >>>>> >>>> Hm...yeah, that makes sense. Are there other things a runtime >>>>>> dependency is meant to do aside from ensure that transitive compile time >>>>>> dependencies are properly tracked? If so, is there a way to solve for >>>>>> the >>>>>> transitive dependencies without removing the runtime dependency? Because >>>>>> ultimately the idea here is that this module is essentially just a big >>>>>> validated/extensible configuration. The resource itself doesn't do >>>>>> anything. So requiring things that refer to a resource to recompile when >>>>>> any of the modules it refers to in a `change` like that is unnecessary. >>>>>> However we can express that reality is totally fine with me. >>>>>> >>>>>> >>>>>> On Sunday, September 11, 2022 at 3:05:18 PM UTC-4 José Valim wrote: >>>>>> >>>>>>> The issue is in the transitive compile time dependencies, not the >>>>>>> runtime dependencies. >>>>>>> >>>>>>> I don't think we should be encouraging removing the runtime >>>>>>> dependencies when they are explicitly listed in the code as above. When >>>>>>> done via configuration, at least you are not literally listing it. >>>>>>> >>>>>>> On Sun, Sep 11, 2022 at 8:59 PM Zach Daniel <[email protected]> >>>>>>> wrote: >>>>>>> >>>>>>>> So all we we do is hold onto the module, and then at runtime we go >>>>>>>> through the list of modules that we should call and call a specific >>>>>>>> function on them. Requiring a runtime dependency for that is causing >>>>>>>> really >>>>>>>> slow compile times because of transitive dependencies. Maybe there is >>>>>>>> some >>>>>>>> consequence I don't see, but I removed the runtime dependencies by >>>>>>>> disabling the lexical tracker when expanding the alias, and its been >>>>>>>> that >>>>>>>> way for months w/o anyone reporting any issues with that >>>>>>>> implementation. >>>>>>>> Aside from having to use `warn: false` if they use aliases. >>>>>>>> >>>>>>>> To me, its the same as if they gave us, instead of a module, an >>>>>>>> `atom` that referred to application configuration, i.e the adapter >>>>>>>> pattern. >>>>>>>> That would work without a runtime dependency, so why couldn't this? >>>>>>>> >>>>>>>> >>>>>>>> On Sun, Sep 11, 2022 at 2:56 PM, José Valim <[email protected]> >>>>>>>> wrote: >>>>>>>> >>>>>>> Sorry, correction: If, at any moment, you call any function from >>>>>>>>> that module at runtime, you must not remove the *runtime* time >>>>>>>>> dependency. >>>>>>>>> >>>>>>>>> On Sun, Sep 11, 2022 at 8:55 PM José Valim <[email protected]> >>>>>>>>> wrote: >>>>>>>>> >>>>>>>> Why do you want to remove the runtime dependency when, per your >>>>>>>>>> description: >>>>>>>>>> >>>>>>>>>> > In Ash Framework, we have declarative ways to construct >>>>>>>>>> *runtime* behavior using behaviors. >>>>>>>>>> >>>>>>>>>> Emphasis mine. If, at any moment, you call any function from that >>>>>>>>>> module at runtime, you must not remove the compile time dependency. >>>>>>>>>> >>>>>>>>>> On Sun, Sep 11, 2022 at 8:52 PM Zach Daniel < >>>>>>>>>> [email protected]> wrote: >>>>>>>>>> >>>>>>>>> `expand_literal` removes the compile time dependency, but leaves a >>>>>>>>>>> runtime dependency when used inside of a module. >>>>>>>>>>> >>>>>>>>>>> What I'm trying to do is remove both the compile time dependency >>>>>>>>>>> *and* the runtime dependency, without requiring the use of `warn: >>>>>>>>>>> false` on >>>>>>>>>>> aliases. >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> On Sunday, September 11, 2022 at 2:31:42 PM UTC-4 José Valim >>>>>>>>>>> wrote: >>>>>>>>>>> >>>>>>>>>>>> Sorry, I don't understand the proposal. You mentioned >>>>>>>>>>>> expand_literal, which already removes the compile-time dependency >>>>>>>>>>>> but keeps >>>>>>>>>>>> the remaining functionality such as warnings. Can you please >>>>>>>>>>>> expand? >>>>>>>>>>>> >>>>>>>>>>>> On Sun, Sep 11, 2022 at 7:57 PM Zach Daniel < >>>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>>> >>>>>>>>>>>>> For clarity, the dependency I'm talking about there is the >>>>>>>>>>>>> dependency from `MyApp.User` to `MyApp.User.Changes.HashPassword`. >>>>>>>>>>>>> On Sunday, September 11, 2022 at 1:55:51 PM UTC-4 Zach Daniel >>>>>>>>>>>>> wrote: >>>>>>>>>>>>> >>>>>>>>>>>>>> In Ash Framework, we have declarative ways to construct >>>>>>>>>>>>>> runtime behavior using behaviors. So an Ash resource might look >>>>>>>>>>>>>> like this: >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> ```elixir >>>>>>>>>>>>>> defmodule MyApp.User do >>>>>>>>>>>>>> use Ash.Resource >>>>>>>>>>>>>> >>>>>>>>>>>>>> alias MyApp.User.Changes.HashPassword >>>>>>>>>>>>>> >>>>>>>>>>>>>> attributes do >>>>>>>>>>>>>> uuid_primary_key :id >>>>>>>>>>>>>> .... >>>>>>>>>>>>>> end >>>>>>>>>>>>>> >>>>>>>>>>>>>> actions do >>>>>>>>>>>>>> create :register do >>>>>>>>>>>>>> change HashPassword >>>>>>>>>>>>>> end >>>>>>>>>>>>>> end >>>>>>>>>>>>>> end >>>>>>>>>>>>>> ``` >>>>>>>>>>>>>> >>>>>>>>>>>>>> However, by default, this would incur a compile time >>>>>>>>>>>>>> dependency. This compile time dependency is unnecessary, as we >>>>>>>>>>>>>> won't call >>>>>>>>>>>>>> any functions on this module or use it in any way until runtime. >>>>>>>>>>>>>> >>>>>>>>>>>>>> That optimization is well and good, but due to transitive >>>>>>>>>>>>>> compile time dependencies, we see some interesting behavior. >>>>>>>>>>>>>> Something >>>>>>>>>>>>>> you'd often see in a change module is things like pattern >>>>>>>>>>>>>> matching on other >>>>>>>>>>>>>> resources, or the resource in question in function heads. >>>>>>>>>>>>>> Resources are >>>>>>>>>>>>>> meant to be introspectable at compile time, and so this runtime >>>>>>>>>>>>>> dependency >>>>>>>>>>>>>> on a change, with a compile time dependency on a resource, >>>>>>>>>>>>>> incurs a >>>>>>>>>>>>>> transitive compile time dependency. This problem multiplies over >>>>>>>>>>>>>> time, and >>>>>>>>>>>>>> causes users to have to do things solely to optimize compile >>>>>>>>>>>>>> times, like >>>>>>>>>>>>>> only use map pattern matches instead of struct pattern matches. >>>>>>>>>>>>>> >>>>>>>>>>>>>> So what we do is we actually disable the lexical tracker when >>>>>>>>>>>>>> accepting certain parts of the DSL. This prevents *any* >>>>>>>>>>>>>> dependency. >>>>>>>>>>>>>> Naturally, at compile time you are no longer safe to call a >>>>>>>>>>>>>> resource's >>>>>>>>>>>>>> change module as changes in that module won't cause recompiles, >>>>>>>>>>>>>> but that >>>>>>>>>>>>>> was never a thing you should have done in the first place so I'm >>>>>>>>>>>>>> not >>>>>>>>>>>>>> worried about that. >>>>>>>>>>>>>> >>>>>>>>>>>>>> This leads us to the primary issue: disabling the lexical >>>>>>>>>>>>>> tracker when expanding aliases also causes warnings about unused >>>>>>>>>>>>>> aliases, >>>>>>>>>>>>>> even though they *are* used. I believe I've brought this issue >>>>>>>>>>>>>> up before >>>>>>>>>>>>>> and we were hoping that the feature introduced in 1.14 for >>>>>>>>>>>>>> `defimpl` would >>>>>>>>>>>>>> help, but that only helps prevent compile time issues, which is >>>>>>>>>>>>>> something I >>>>>>>>>>>>>> had already solved for in the same way it was solved for 1.14. >>>>>>>>>>>>>> I've laid it >>>>>>>>>>>>>> all out to help clarify exactly *why* I need it so perhaps >>>>>>>>>>>>>> someone can >>>>>>>>>>>>>> point me in a better direction. >>>>>>>>>>>>>> >>>>>>>>>>>>>> The simplest thing that could help: >>>>>>>>>>>>>> >>>>>>>>>>>>>> A way to tell the lexical tracker that an alias has just been >>>>>>>>>>>>>> referenced without inducing any kind of compile or runtime >>>>>>>>>>>>>> dependency. The >>>>>>>>>>>>>> idea is to just prevent it from warning about the alias. >>>>>>>>>>>>>> >>>>>>>>>>>>>> I'm open to other solutions as well. >>>>>>>>>>>>>> >>>>>>>>>>>>> -- >>>>>>>>>>>>> You received this message because you are subscribed to the >>>>>>>>>>>>> Google Groups "elixir-lang-core" group. >>>>>>>>>>>>> To unsubscribe from this group and stop receiving emails from >>>>>>>>>>>>> it, send an email to [email protected]. >>>>>>>>>>>>> To view this discussion on the web visit >>>>>>>>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/54627973-7b74-47d7-9e35-4270621e6c91n%40googlegroups.com >>>>>>>>>>>>> >>>>>>>>>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/54627973-7b74-47d7-9e35-4270621e6c91n%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>>>>>>>>> . >>>>>>>>>>>>> >>>>>>>>>>>> -- >>>>>>>>>>> You received this message because you are subscribed to the >>>>>>>>>>> Google Groups "elixir-lang-core" group. >>>>>>>>>>> To unsubscribe from this group and stop receiving emails from >>>>>>>>>>> it, send an email to [email protected]. >>>>>>>>>>> >>>>>>>>>> To view this discussion on the web visit >>>>>>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/22887a7e-a1b6-4ccc-98bf-69a5ad3551a5n%40googlegroups.com >>>>>>>>>>> >>>>>>>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/22887a7e-a1b6-4ccc-98bf-69a5ad3551a5n%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>>>>>>> . >>>>>>>>>>> >>>>>>>>>> -- >>>>>>>>> You received this message because you are subscribed to the Google >>>>>>>>> Groups "elixir-lang-core" group. >>>>>>>>> >>>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>>>> send an email to [email protected]. >>>>>>>>> >>>>>>>> To view this discussion on the web visit >>>>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2BVkL%2B1V7LTDVyzhCqcNWrmHFPoWx2Fp916Ur%2ByL%2BiVBA%40mail.gmail.com >>>>>>>>> >>>>>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2BVkL%2B1V7LTDVyzhCqcNWrmHFPoWx2Fp916Ur%2ByL%2BiVBA%40mail.gmail.com?utm_medium=email&utm_source=footer> >>>>>>>>> . >>>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>>> You received this message because you are subscribed to the Google >>>>>>>> Groups "elixir-lang-core" group. >>>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>>> send an email to [email protected]. >>>>>>>> >>>>>>> To view this discussion on the web visit >>>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/l7xp6eut.444ff913-f528-4b88-805a-cac120cdb4d6%40we.are.superhuman.com >>>>>>>> >>>>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/l7xp6eut.444ff913-f528-4b88-805a-cac120cdb4d6%40we.are.superhuman.com?utm_medium=email&utm_source=footer> >>>>>>>> . >>>>>>>> >>>>>>> -- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "elixir-lang-core" group. >>>>>> >>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>>> an email to [email protected]. >>>>>> >>>>> >>>>>> To view this discussion on the web visit >>>>>> https://groups.google.com/d/msgid/elixir-lang-core/072bb99d-09a0-4567-a934-f8893015dd91n%40googlegroups.com >>>>>> >>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/072bb99d-09a0-4567-a934-f8893015dd91n%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>> . >>>>>> >>>>> -- >>>>> You received this message because you are subscribed to the Google >>>>> Groups "elixir-lang-core" group. >>>>> >>>> To unsubscribe from this group and stop receiving emails from it, send >>>>> an email to [email protected]. >>>> >>>> >>>>> To view this discussion on the web visit >>>>> https://groups.google.com/d/msgid/elixir-lang-core/l80s9s37.13dfe243-83b3-4133-8aad-7a86910f56fa%40we.are.superhuman.com >>>>> >>>>> <https://groups.google.com/d/msgid/elixir-lang-core/l80s9s37.13dfe243-83b3-4133-8aad-7a86910f56fa%40we.are.superhuman.com?utm_medium=email&utm_source=footer> >>>>> . >>>> >>>> >>>>> -- >>>> >>> You received this message because you are subscribed to the Google >>>> Groups "elixir-lang-core" group. >>>> >>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to [email protected]. >>>> To view this discussion on the web visit >>>> https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4J8qxM%3DKxMUUW6X%2Bt%2BrD9rKn0yDHbDY1fDgopxRvtNn5A%40mail.gmail.com >>>> >>>> <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4J8qxM%3DKxMUUW6X%2Bt%2BrD9rKn0yDHbDY1fDgopxRvtNn5A%40mail.gmail.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>> >>> -- >> You received this message because you are subscribed to the Google Groups >> "elixir-lang-core" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to [email protected]. >> > To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/325ea272-674a-4a5a-9228-6af11579bd05n%40googlegroups.com >> >> <https://groups.google.com/d/msgid/elixir-lang-core/325ea272-674a-4a5a-9228-6af11579bd05n%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/73a308e4-59e9-4f23-bb92-1417855cc996n%40googlegroups.com.
