This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-08-01
Channels
- # aleph (3)
- # announcements (10)
- # babashka (6)
- # bangalore-clj (4)
- # beginners (91)
- # biff (7)
- # cider (25)
- # cljs-dev (1)
- # clojure (109)
- # clojure-europe (9)
- # clojure-norway (5)
- # clojure-uk (1)
- # clojurescript (22)
- # cursive (22)
- # data-science (1)
- # datalevin (5)
- # datomic (7)
- # emacs (7)
- # etaoin (1)
- # events (3)
- # graphql (12)
- # hyperfiddle (1)
- # inf-clojure (1)
- # lsp (69)
- # luminus (1)
- # meander (21)
- # nbb (4)
- # off-topic (27)
- # other-languages (12)
- # rdf (58)
- # releases (3)
- # remote-jobs (2)
- # rum (12)
- # shadow-cljs (4)
- # sql (3)
- # xtdb (1)
One feature of Elixir I can't tell is madness or genius or both, but it's the backbone of the Phoenix framework and why they managed to make a framework feel similar to Rails in my opinion, is the use
keyword and using
macro.
You can read a bit about it here: https://brooklinmyers.medium.com/using-use-usefully-in-elixir-and-phoenix-b59a5ea08ad2
I think you can do the same in Clojure, without any changes to the language either, it's kind of just a convention, though you'd need to require some things so it be a little less magic.
Basically, it's like calling a macro from another namespace at the top-level of your namespace which will return a bunch of top level code injected into your own namespace. That code could itself require or import more things into your namespace or call more of those injecting macros from other namespaces.
Think something like:
(ns foo)
(defmacro using []
`(do (require [clojure.string :refer :all])
(defn render [name]
(join "," ["Hello" name "welcome!"]))))
(ns bar)
(foo/using)
It kind of end up being used similar to inheritance in OOP, so one Elixir module inherits from another, but it's done literally by just capturing the code from another module into your own through the use of a macro. It's hard to know if that means it has all the same problem inheritance has or not... But it's magic in that it can turn a module into a convention with a lot of default functionality loaded in and some extension points. And it can also automatically require and refer a bunch of stuff.
Compare:
defmodule TodoWeb.ItemsController do
use TodoWeb, :controller
alias Todo.Items
def index(conn, _params) do
items = Items.list_items()
render(conn, "index.html", items: items)
end
end
with:
package TodoWeb;
import Todo.Items;
class ItemsController extends TodoWebController
public index(conn, params) {
var items = Items.listItems();
this.render(conn, "index.html", items);
}
}
Why not create a module interface and use Java inheritance? Also this could then allow to use some kind of dependency injection or parameter-based extension and not inheritance
What do you mean module interface? In Elixir they don't have inheritance, similar to Clojure. So in order for a namespace to automatically have some functions and variables "inherited" from a base, it uses a macro to copy them over. The result is not just that you can use those from inside the namespace, but that other namespaces can use them from your namespace.
I meant to use Java's interface. But I see that you want to use a macro. Which is fine. I haven't used Ruby but I think it's OOP. So why not reuse Java with Clojure's defrecord
and reify
. :thinking_face:
It's not Ruby, it's Elixir, they share a similar syntax. Interfaces and therefore defrecord/defprotocol doesn't get you the same thing as inheritance. Which is why people in Elixir came up with this strange macro instead. The macro can pull in vars, requires, imports as well as functions.
https://clojureverse.org/t/namespace-inheritance-a-la-elixir-use-using-is-this-madness/9199
I honestly hate the use
macro
I had SO MANY libraries I could not use outside Phoenix, or ExUnit, or things like that because these libraries expected me to use SomethingFromPhoenix
or whatever
Sure, I could track which functions I was not implementing and provide mocked versions for it, but again, this all could be avoided if use
didn't exist at all, so library authors would not be able to "cut corners" like that...