4 ms·
I personally don't have any problem with heavy macro-use in libraries, I feel like that is where they shine. So long as the documentation is good, I don't real
by sodapopcan 3y ago
I personally don't have any problem with heavy macro-use in libraries, I feel like that is where they shine. So long as the documentation is good, I don't really care how the library itself is implemented. I would much rather have the cleaner API in many cases. I know it can be taken too far, though. Some funky stuff can happen in Phoenix's router, though a lot of it is actually to reduce cyclic compile-time dependencies as the router is a place where these necessarily happen.
Macros in business code, however, are pure evil. I feel like anyone who spent any time in Rails over the past decade has learned that lesson.
- throwawaymaths 3y agoYep. I wish `pipeline`, `scope` and `resources` in Phoenix router and also all the `use MyApp.Web, :x`, would just die in a fire. Thank goodness they got rid of views though I still am annoyed that the default path resolution on templated content isn't explicit. The crazy thing is that the most amazing part of phoenix, liveview, is almost no macros.
- sodapopcan 3y agoI never use `resources` though have no beef with `pipeline` or `scope`, though I haven't thought too much about it. It is a little weird getting used to which modules are getting auto-qualified and which aren't, but I'm long passed that. And that is actually what is "fixing" the cyclical dependency issue. What's wrong with the `use MyApp.Web, :x`? You can easily get rid of it as it's just generated boilerplate. It's a nice little pattern to allow all the different things to share the view helpers. If you'd like to be extra explicit, though, just delete the file and include everything manually. I'm indifferent on views because I never really used them, haha.
- halostatue 3y agoI personally would prefer something like: defmodule MyApp.Web.Router do use MyApp.Router end over defmodule MyApp.Web.Router do use MyApp, :router end but that’s a preference.
- sodapopcan 3y agoYou can do that if you want. Just remove `def router` from `MyAppWeb` move its contents over to a custom module: defmodule MyAppWeb.Router do defmacro __using__(_) do quote do use Phoenix.Router, helpers: false import Plug.Conn import Phoenix.Controller import Phoenix.LiveView.Router end end end But why the dislike for passing a second argument to `use`? It keeps everything together pretty nicely.
- halostatue 3y agoMostly because we’re using an umbrella at the place of work, and we absolutely don’t want those boundaries crossed.
- sodapopcan 3y agoOh! Well I don't know your setup but you could always add a top level `PhoenixHelpers` namespace (or a better name) that holds these generic types of things that can be shared between apps. Though again I really don't know your set up. Like maybe you have an app whose router doesn't need `Phoenix.Controller` so then this wouldn't make sense.
- arrowsmith 3y ago> I wish `pipeline`, `scope` and `resources` in Phoenix router and also all the `use MyApp.Web, :x`, would just die in a fire. How would you prefer it worked/looked? > I still am annoyed that the default path resolution on templated content isn't explicit. What do you mean by this? In the new 1.7 approach to views, you explicitly set the path in each view using `embed_templates` (if you're not defining your HEex directly within the view module itself.) What part isn't explicit?
- throwawaymaths 3y ago> What do you mean by this? In the new 1.7 approach to views, you explicitly set the path For example, if you wrote a liveview called FooView in /path/to/my_liveview, a default render() will look for /path/to/my_liveview/foo_view.html.heex (Also note auto-snakecasing) Btw, this is still a different semantic if you do the deadview equivalent, which will try to do a path resolution in /templates. I guess these are minor complaints but I would much prefer they use the same default strategy and, say, pass the path in `use Phoenix.Liveview`
- arrowsmith 3y ago> This is still a different semantic if you do the deadview equivalent, which will try to do a path resolution in /templates. Not true in 1.7 - views* don't have any kind of "default" template resolution; you have to explicitly state the template path with `embed_templates`. That is if you're not just defining your HEEx directly within the view module itself, as I already mentioned. *By "views" I mean the new style that uses `use MyAppWeb, :html`, not the old style you describe which is now (in 1.7+) only available as the external dependency `phoenix_view`. The new style of module is still called a "view" by the docs: https://hexdocs.pm/phoenix/request_lifecycle.html#from-endpoint-to-views https://hexdocs.pm/phoenix/request_lifecycle.html#from-endpo...
- jrochkind1 3y ago> So long as the documentation is good, I don't really care how the library itself is implemented. I don't have experience in Elixir, but in my general experience what you say is fine until you need to debug something going wrong (or something you don't understand and _think_ is going wrong) in a library, which always happens eventually, no? Or until you want to PR a feature, etc.
- throwawaymaths 3y agoYour intuition as a nom-elixir user is absolutely correct. However it's worth saying that as a working dev, there's almost never a problem in the core++ libraries. Edit: lol looking at the log in elixir slack, and one of the most recent posts is exactly trying to debug something too magical in one of the aformentioned non-core++ libries!!
- sodapopcan 3y agoThose are fair points. In terms of PRing, though, I do think that people are a little too "afraid" of macros. It sometimes feels like people won't learn them out of of principle which is a shame as they aren't that complicated. Though anyone trying to navigate nested macros definitely has my sympathy. No matter how slice it, however, macros are a massive part of what makes Elixir Elixir. A large portion of the language's "keywords" are just macros and they reduce a lot of the boilerplate Erlang forces you to write.
- throwawaymaths 3y agoEEx does macros well. Note that EEx.function_from_x makes you declare the name of the function it instantiates, so it's searchable. GenServer is kind of a "bad example" of a macro. It creates a totally hidden function. Though I guess to be fair 99.9% of the time you really shouldn't be writing genservers in elixir.
- AlchemistCamp 3y ago> 99.9% of the time you really shouldn't be writing genservers in elixir Woah! Why is that? I've written at least one GenServer in nearly all the Elixir projects I've worked on. They seem like one of the base building-blocks to me. Also, if you squint a bit, you'll see that many libraries you're working with are essentially exposing a GenServer interface, with a few extra features.