jmitchell

jmitchell

What is the best practice for implementing a library for use in both Elixir and Erlang? My goals include:

  1. minimize code duplication
  2. feels idiomatic to both Elixir and Erlang users
  3. no syntactic function call remapping like :lists.sort [3, 2, 1] or 'Elixir.String':downcase(Bin).
  4. integrates seamlessly with common package management and build solutions
  5. doesn’t break any features like maybe hot code reloading (or anything else, really)
  6. written primarily in Elixir because I like defmacro.

Without knowing better, the first strategy I’d probably try is implementing an Elixir library and making an Erlang wrapper. This seems good, except I’d have to manually keep the wrapper synced with the Elixir code. Are there recommended wrapper generators for this?

I’m not familiar enough with Elixir/Erlang/BEAM to know whether that approach might break any features. If so, would writing the library primarily in Erlang be any better?

I don’t have a specific project in mind yet. Just mulling over how I would approach this when the time comes. Thanks, everyone.

Showing Posts 1 to 10

jwarlander

jwarlander

I don’t have any other certain answer than the wrapper solution (which would of course work, but as you say be a bit annoying to maintain). However, it feels like this should be possible to solve by some kind of compile-time transformation of module / function names, so that you could compile to two different outputs from the same source.

That being said, it looks like it could be done using defdelegate in a compile-time-dynamic fashion, eg:

I won’t say much about if it’s a good idea or not, but at least it works for this simple example :wink:

michalmuskala

michalmuskala

What I saw frequently in Erlang codebases using Elixir is the use of macros to alias elixir modules into something more consumable. You could provide an erlang header file that would provide some of those macros, eg:

-define(string, 'Elixir.String')
# later in code
?string:downcase(Bin).

On the other hand, I don’t see anything wrong with calling erlang-style modules from Elixir. You could use those:

defmodule :foo do
  # ...
end
# use in elixir
:foo.bar(1, 2, 3)
# use in erlang
foo:bar(1, 2, 3).

In general I would say that a wrapper is the worst approach - it doesn’t add any significant value and has considerable downsides and risks regarding it getting out of sync.

jmitchell

jmitchell OP

I didn’t know about Erlang-style module support in Elixir. Thanks for mentioning it!

vic

vic

Asdf Core Team

So if @jmitchell would like to be able to call Foo.bar nicely from both Elixir and foo.bar from Erlang, would this be an acceptable approach to expose the api for both ?

defmodule Foo.Impl do
  defmacro __using__(_) do
    quote do
      def bar(), do: # ...
     # more of Foo public API
   end
  end
end

defmodule :foo do
   @moduledoc "For use from erlang"
   use Foo.Impl
end

defmodule Foo do
   @moduledoc "Alchemist way"
   use Foo.Impl
end
PragTob

PragTob

This seems great btw. I implemented this in benchee now and we’ll see how it turns out but it was super easy to do and even the doc generation etc. is alright. I have yet to really try this under erlang but I see no problems coming my way… thanks a lot @vic!

PragTob

PragTob

So, @josevalim came around and suggested another way to do this which I like better as it is simpler:

elixirdoc = """
...
"""

erlangdoc = """
...
"""

for {module, moduledoc} <- [{Benchee, elixir_doc}, {:benchee, erlang_doc}] do
  defmodule module do
    @moduledoc moduledoc
    # all defs here without using
  end
end

It is implemented in this benchee PR.

Crowdhailer

Crowdhailer

Creator of Raxx

This feels like an odd solution because it seams like a load of code is being duplicated.

However I am super happy that this problem is being tackled. Just need to wait and see how macros can be useful to erlang.

PragTob

PragTob

do you mean the old solution, the new one or both? :slight_smile:

Imo no code is duplicated, depending on the meaning of “duplicated”. I.e. no code in my files is duplicated, I just have to change a thing in one place and it changes everywhere I want it to change. So that’s no duplication for me.

If we are talking about compiled duplication, sure there is. For my understanding of use it is the same for both solutions though (I might be wrong). Also, does it matter? It won’t impact the compiled size to a meaningful degree. If we were on a JITing VM we could argue that they are JITed which might be suboptimal. Alas, we are not. Also, the interfaces are meant to be used as either or (elixir or Erlang) so someone using both would be unlikely.

Or am I missing some other duplication? :slight_smile:

Crowdhailer

Crowdhailer

Creator of Raxx

The duplication I was talking about here was the compiled duplication. I was curious if the compiled artifact was twice the size.

I have tried another solution in this PR. comments/criticism welcome.
https://github.com/CrowdHailer/raxx/pull/112/files

PragTob

PragTob

Not sure about the compiled artifact size but as it’s just one top level module that does a bunch of delegates to other things I don’t think the size impact (even if it duplicates all that code) is worth worrying about as I’d say it’s maybe ~1% of the overall code size.

I like the solution because it’s very simple and uses the simplest constructs to make it work - i.e. no macros.

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews