Qqwy

Qqwy

TypeCheck Core Team

So while writing Confy, I wanted to turn shorthand atoms like:integer, :string, :atom into the ‘normal’ forms &Confy.Parsers.integer/1, &Confy.Parsers.string/1, &Confy.Parsers.atom/1, etc.

However, I struggled to properly perform quoting and unquoting while using the function capture operator&.

In the end, I settled on the following snippet:

  # Replaces simplified atom parsers with
  # an actual reference to the parser function in `Confy.Parsers`.
  # NOTE: I dislke the necessity of `Code.eval_quoted` here, but do not currently know of another way.
  defp normalize_parser(parser) when is_atom(parser) do
    case Confy.Parsers.__info__(:functions)[parser] do
      nil -> raise ArgumentError, "Parser shorthand `#{inspect(parser)}` was not recognized. Only atoms representing names of functions that live in `Confy.Parsers` are."
      1 ->
        {binding, []} = Code.eval_quoted(quote do &Confy.Parsers.unquote(parser)/1 end)
        binding
    end
  end
defp normalize_parser(other), do: other

Note the Code.eval_quoted line: Although it is probably safe since it is only executed when parser indeed is an atom and exists as a function inside the Confy.Parsers module, it does not feel nice to need it.
Is there another way to build a function capture out of a module and function atom?

Note that 'function captures like wrapping everything with fn are not what I am looking for, since the result of normalize_parser is also used to create documentation:
inspect(&Module.foo/1) is "&Module.foo/1" whereas
inspect(fn x -> Module.foo(x) end) is "#Function<6.127694169/1 in :erl_eval.expr/5>".

Thanks! :smile:

Showing Posts 1 to 5

OvermindDL1

OvermindDL1

Would not &apply(Confy.Parsers, parser, [&1]) work? :slight_smile:

apply/3 is so very useful. ^.^

iex(1)> h apply/3

                     def apply(module, function_name, args)                     

  @spec apply(module(), function_name :: atom(), [any()]) :: any()

Invokes the given function from module with the list of arguments args.

apply/3 is used to invoke functions where the module, function name or
arguments are defined dynamically at runtime. For this reason, you can't invoke
macros using apply/3, only functions.

Inlined by the compiler.

## Examples

    iex> apply(Enum, :reverse, [[1, 2, 3]])
    [3, 2, 1]

Consequently it has no speed hit over a normal indirect call either since they lower to the same beam code, just to be sure I’ve also benchmarked it. ^.^

OvermindDL1

OvermindDL1

Also instead of this, this is faster:

if function_exported?(Confy.Parsers, parser, 1) do
iex(2)> h function_exported?

                def function_exported?(module, function, arity)                 

  @spec function_exported?(module(), atom(), arity()) :: boolean()

Returns true if module is loaded and contains a public function with the given
arity, otherwise false.

Note that this function does not load the module in case it is not loaded.
Check Code.ensure_loaded/1 for more information.

Inlined by the compiler.

## Examples

    iex> function_exported?(Enum, :member?, 2)
    true
Qqwy

Qqwy OP

TypeCheck Core Team

Using function_exported? is definitely the way to go. Thank you, I did not know about that function!

As for using apply: It would end up in the documentation as well:
See f.e. here:

Validated/parsed by calling &Confy.Parsers.boolean/1 .

this would then become

Validated/parsed by calling &apply(Confy.Parsers, :boolean, [&1]) .

which is not nearly as nice.

Thus I really am looking for a way to construct &SomeModule.foo/1 where foo is a dynamic value.

If there is no way around sing Code.eval_quoted then that is fine, but I did want to check :slight_smile:.

hauleth

hauleth

Function.capture/3 is what you are looking for.

axelson

axelson

Scenic Core Team

Wow, there’s so many little goodies in the stdlib. Never ceases to amaze me.

— All posts loaded —

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
peck
Hi everyone. My team and I have been working on a fairly modest app based around video streaming and chat, but we’ve landed a customer t...
New
achenet
Hello, I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind. However, when I launch mix phx.server, I get an error...
New
bradley
I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management servic...
New
unaware8150
Hello folks! So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
Alvinkariuki
How Can I Optimise Compile Time Dependencies I have been building an elixir application for about 2 years now. Many modules and files ha...
New

Other Trending Topics Top

budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
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
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews