stephanos

stephanos

Hi!

I’ve been tinkering with bringing Clojure.spec to Elixir (I’m aware of prior art here, but want to experiment with a different syntax).

Having never dabbled in meta programming before, I’m curious to learn if I hit a wall or if I’m missing something.

Here is some simple pseudo-code

  @arg a: is_integer(), is_integer()
  @arg b: is_integer()
  @ret is_integer()
  def add(a, b) do
    a + b
  end

I discovered that @ is a macro in the Kernel module and appears to be evaluated before I get a chance to do anything (via before_compile, on_definition or my macro). Right now it fails because is_integer() isn’t valid.

Is there any way to transform the AST to replace the module attribute with my own code?

I’ve learned about the possibility of a custom defmodule implementation but that seems excessive to me. I considered using function references, like &is_integer/1 but it seems a bit ugly to me (very subjective ;). It also appears that I can’t override the @ macro easily since I’m getting “call is ambiguous” when I define my own. Are these all available options?

Thank you!
Stephan

Showing Posts 1 to 4

christhekeele

christhekeele

Hey, welcome to the ElixirForum, and Elixir meta-programming!


I think the conceptual nudge that will help you the most here is a little clarification in the role of various concepts during the compilation process:

  • a Module is a unit of compilation + a namespace
  • a module attribute is a constant language-level value determined at compile time
  • a Macro is a special function executed at compile time that receives AST as input and places its return value into the AST where invoked
  • macros can access module attributes, ie in compilation hooks via attribute functions.

Emphasis on value. What you place in a module attribute should be a language-level primitive value, that may be operated on later by compile-time hooks. You’ll notice the input to all documented module attributes, with the exception of type-related stuff, are just tuples, lists, strings, atoms, etc.

Typespec-related attributes get special builtin compiler-powered semantics and expressivity, that I do not think you can tap into in user-land code.

You cannot place arbitrary typespec syntax into an arbitrary module attribute today.


The easiest way to get this is to use macros, which specialize in AST transformation. You should try offering, for instance, defarg and defret macros. They could emit type-spec related module attributes AST compatible with the type system. Macros are more than capable of consuming the typespec syntax and operating on it, doing library magic with it, and re-emitting the syntax into typespec module attributes.

As an alternative, you could invent a language-level data primitive syntax that expresses what you want, like @arg a: [:is_integer, :is_integer], and compile it into a typespec via a compilation hook (and perform your library’s magic in the same pass).

The takeaway here, though, is that you’ll need to leverage macros get what you want, with module attributes as possible input to them and output from them.


One note:

You definitely don’t want to do this–even if it is possible (which would surprise me) overriding module attribute definition would have a high chance of breaking tons of stuff in caller code. @ is a macro in the Kernel module for documentation and compiler bootstrapping purposes only.

Qqwy

Qqwy

TypeCheck Core Team

Overriding the @-macro is possible, and is in fact what Norm does to allow custom macro-expansion in the ‘@contract …’ notation. (c.f. norm/lib/norm/contract.ex at master · elixir-toniq/norm · GitHub)

I do think that this solution is a bit of a hack. For instance, it would not be possible to use multiple libraries that each try to override @ unless they pay special attention to how they do the fall-back.

stephanos

stephanos OP

@christhekeele Thank you, I really appreciate that insight - and the warm welcome!

@Qqwy ha, I guess I wasn’t aware of this Clojure.spec-like implementation - that’s pretty close to what I was imagining. The generator-side of this is what I find the most intriguing.

christhekeele

christhekeele

That’s pretty cool. Still dark magicks, but now I wanna play with it!

— 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
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
AstonJ
Since we have deprecated our Erlang sections (as we have dedicated Erlang Forums now) let’s add this thread for those who’d like to post ...
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

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
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

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews