massimo

massimo

I was recently made aware of a new programming language, the Roc language that is still in early development stage, but looks very interesting on many aspects, especially the fact that it took a lot of ideas from Elixir.

In particular it uses the <- operator as syntax sugar over async operations, for example

a <- File.read(filename)

is automatically tranlsated to

a = Task.async(fn -> File.reade(filename) end) |> Task.await()

and I was wondering if I could implement the same behaviour using Elixir macros.

Turns out it was easier than I thought.

I don’t know if anyone is going to ever find this useful, but here it is, in all its glory.

defmodule Roc do
  defmacro a <- b do
    quote do
      retval = case unquote(b) do
        t = %Task{} -> Task.await(t)
        f when is_function(f) -> Task.async(f) |> Task.await()
        _ -> raise ArgumentError, message: "parameter b must be a Task or a function"  
      end
      var!(unquote(a)) = retval
    end
  end
end

and can be used this way

c <- Task.async(fn -> :return_value end)

d <- fn -> :function end

try do
  _e <- 2
rescue
  ex -> IO.inspect(ex)
end

IO.inspect({c, d})

# --- OUTPUTS
%ArgumentError{message: "parameter b must be a Task or a function"}
{:return_value, :function}

Showing Posts 1 to 3

dimitarvp

dimitarvp

If you are interested in research in this area then you might also find the Alan language interesting.

al2o3cr

al2o3cr

IMO this doesn’t quite capture the whole thing going on with ->; it’s missing the sequencing aspect of it.

From the “A Taste of Roc” talk:

This is the desugared form of:

username <- await (File.read "username.txt")
res <- await (Http.get "foo.com/\(username)")
File.write "response.txt" res

The presentation didn’t say it explicitly (at least not in the part I watched) but in addition to the above I assume Roc’s await is also doing some Result-monad gyrations to ensure that error values bubble out, ala Elixir’s with.

Note that starting a task and then immediately awaiting it in Elixir is kind of useless - the calling process is blocked while the Task executes and crashes if the task crashes. The “start then await” pattern is more of a Node idiom where await is the way to hand control back to the runtime.

massimo

massimo OP

Of course there’s no way that a 5 lines macro could replace the work being done on a compiler at the language level.

That wasn’t even the point.

As far as I understood what Roc does is “simply” avoid the callback hell, by ensuring that each call will wait until completion before the next one is started. The compiler can have a broader look on code at large, so has more information to optimize the calls, but what is doing is exactly “start and then await”, which is not bad per se. The calling process is blocked anyway when you await on something, in any language, or the order of the execution could not be guaranteed.
That doesn’t exclude that A is run concurrently with another computation somewhere else.

The indentation visible in the image you posted is used to scope the variables, every indentation in Roc creates a new scope (at least that was my understanding)

I don’t understand the error bubbling remarks: if the function being called return an error tuple, the error will be returned, if it raise an exception, the exception can be caught.

with gets a little help from the compiler

defmacro with(args), do: error!([args])

defmacrop error!(args) do
    quote do
      _ = unquote(args)

      message =
        "Elixir's special forms are expanded by the compiler and must not be invoked directly"

      :erlang.error(RuntimeError.exception(message))
    end
  end

Anyway, it was simply an exercise in metaprogramming to explore the possibility, I really thought it was not possible in Elixir, but I was wrong.

That’s why it’s posted in chat/discussions :slight_smile: :slight_smile:

— All posts loaded —

Where Next? Top

Trending in Discussions Top

AstonJ
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
2977 94592 917
New
cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
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
heathen
Quite interesting article Google brought me. Didn’t find any mentions about it here. What do you think in general? Would you use togethe...
New
maennchen
:warning: Security advisory: Decimal DoS vulnerability A vulnerability has been published for decimal where very large exponents can cau...
New
marciol
It would be helpful to have a list of companies worldwide that hire engineers without prior experience in Elixir. Often, it can be quite ...
New
Null-logic-0
What IDE or editor are you using for Elixir development? Personally, I use Zed, and I really like it, but sometimes I wish there were a ...
New

Other Trending Topics Top

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
webofbits
Aludel - LLM Evaluation Workbench Aludel is an embeddable Phoenix LiveView dashboard for evaluating and comparing LLM prompts across mult...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews