How to define a function dynamically on a given line

I need a way to make a function or macro available at the beginning or top of a module, I thought I could find a way to define a function dynamically on a given line and see if that works, but no leads.

You seem to be explaining a potential solution that you feel will solve your problem.

Could you please describe your problem instead?

4 Likes

That is true :cold_face:

The problem is i’m invoking ‘use’ and it’s functions are not available above the line it is being invoked on, but it must.

You can’t. Imports a lexically scoped.

If though your use does use a quoted def/2 to inject a function it would work. But this is bad practice.

Better practice is to not use something from the use before the use.

1 Like

I understand, thanks for the info. Where can I find more information on the bad practice of using quoted def/2’s?

I have no written evidence I could show you right now. But it seems to be common sense throughout the forum and the slack to avoid defining or even importing functions into the users module, without giving them a way do opt-out.

If you def something, then you make this very hard, to still provide the necessary functionality.

If though you use import, you can accept a :only or :except option in the args and pass it through to import, but the user can still use the functions by calling the not-imported functions qualified.

This way, you do not shrink the available namespace by injecting functions/names the user probably never want to call.

I see.

I tried using quote line: 1 do ... as it appears to override the lines throughout the expression. It compiles but the functions are still unavailable.

That does only affect messages of the compiler, it does not move around actual code.

And you still haven’t told us, why you need the functions before use. There is usually no reason to, as use should be one of the first lines in a module.

It imports a macro that’s used to read the content of a file and embed it in doc annotations. @moduledoc comes before anything else, so i wanted to see if I could avoid breaking that convention.

I realise that the contents could simply be copied and pasted but for my use case that would be cumbersome and otherwise disturb its purpose.

Sorry, I can’t follow you. Can you please show an example that shows why you can’t generate the module doc in the use? Or do I understand something wrong?

defmodule TheModule do
    @moduledoc"""
    stuff
        #{embed_in_doc("file")
    """

    use UsedModule
...

If it’s only that, get rid of use and qualify the function call.

That way it would look like this:

defmodule TheModule do
    require UsedModule

    @moduledoc"""
    stuff
        #{UsedModule.embed_in_doc("file")}
    """

    use UsedModule
...

It’s a macro.

Is there a reason for it beeing a macro or would a function be sufficient?

1 Like

It needs information accessible only through a macro in order to find the right file for the given module.

Seems to be to much magic involved. Just specify full path, or require to pass in the data necessary.

I’m not even sure what the benefit is over a simple File.read!/1.

The whole point was to avoid all of those things, as it would get quite bloated.

I don’t think we will be able to agree on this, but at the end your only option is to require/import before using the macro for the first time.

:disappointed_relieved: