Macros called from Macros

Hi everybody,

My team wants to get rid of the need to explicitly write _ = Logger.info(...) to ignore the result of the logging function (which is actually a macro). We though of writing macros doing exactly this behind the scenes while making still Dialyzer happy. So my question is twofold in fact:

  • Is systematically ignoring the result of the logging macros that bad?
  • Is calling/using a macro within a macro harmful, just a bad practice or plain OK?

Thanks in advance

2 Likes

If you want to ignore the result of Logger.info you can just not capture the result. It won’t be returned from a function unless it’s the last expression in the function anyway. What is the issue you’re seeing with this?

Logger.info "wat"
# do other stuff here

As for the more extended question, any macro that is using def, et. al. is using macros. It’s a question that pretty much amounts to “Does this have the capacity to become confusing?” and the answer is that it depends on how clear and well designed the components you’re using are.

I don’t think it’s valuable to make the distinction between macros and function in terms of using them inside macros, but instead think about how clear the implementation is with regards to “Is it using a lot of implicit stuff or not?”, etc.: Questions that relate to how easy it is to see what is happening.

1 Like

The issue with your version is, that dialyzer complains about not using a functions return value. To get rid of dialyzers warning it is a common pattern to match its call against _ to explicitely tell dialyzer: “I know here is a result, but I don’t care and call for sideeffects only”.

@fcabestre, this may be my personal opinion, but I really do not like hiding things that are explicit by default behind some macro to make them implicit. Either use the _-pattern or try to configure dialyzer per module by using dialyzer-attributes.

3 Likes

@gon782 Well… That’s perfectly right :smiley: and it’s what we usually do. But, as pointed by @NobbZ, Dialyzer complains because we’re not using the returned value and that’s we want to avoid. I’m not quite confortable ether with hiding this behind a macro, and we probably should find a way to shut Dialyzer up about this. Is there any way to do that just for calls to Logger.xxx()?

Anyway, macros called from macros is a fine pattern in Elixir as it is in Lisp. I’m ok with that, I just wanted to be sure :wink:

1 Like

You could make a wrapper for your logging call and then exclude it from Dialyzer checks by writing the following in the code (I assume this works for Elixir as well):

@dialyzer nowarn_function: &logging_wrapper/1 but that would turn off all warnings for that function. Given that it’s presumably a very thin wrapper it shouldn’t matter. You could also specify much more than that and the module attribute details are available here: dialyzer doc page

I’m inferring that this is how you’d specify it in Elixir and also that it’ll work, but I don’t see how else you’d represent that attribute and I don’t see why it wouldn’t work either.

Thank you for all your hints