otobus / event_bus

:surfer: Traceable, extendable and minimalist **event bus** implementation for Elixir with built-in **event store** and **event watcher** based on ETS.

Home Page:https://hexdocs.pm/event_bus

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Dialzyer warnings in EventSource.notify (even in EventSource.build )

xadhoom opened this issue · comments

With a simple call like:

EventSource.notify %{topic: :my_topic} do
      %{account: foobar, error: "some"}
end

Dialyzer warns about The pattern {'error', __@4} can never match the type....
Code in the macro seems correct, but maybe dialyzer goes mad about it?

As a side note, a macro is really needed for EventSource.build and EventSource.notify funs? Why not a simpler EventSource.build(params, fun) where fun is the the current do/end block? After all, everything done in those macros are executed a runtime, so no real need for the macro.

Or I'm totally wrong?

Probably, your dialyzer got crazy. It sometimes doesn't recognize even recognize with/do/else blocks. Here is a sample that passes the dialyzer:

https://github.com/mustafaturan/messenger_bot/blob/master/lib/messenger_bot/web/services/setup.ex#L26-L28

Sorry for above comment: I see the mistake, you should return {:error, any()) tuple to satisfy dialyzer:

EventSource.notify %{topic: :my_topic} do
   # should return `{:error, any()}` or `any()`
end

In your case, you are only returning any() which breaks the contract for dialyzer

Well, not exactly.

Right now having a case to check result from yield block you are required to return both, based on different paths on the yield block code.
This basically happens because while the macro expands you have a code where a branch cannot simply happen, like

case fun do
 {:error, :foo} -> ...
 any -> any
end

and fun is something: def fun, do: any . So dialyzer is correct here.

There're two possibile solutions:

  • avoid macros, since almost everything can be done with just passing functions (I have to check how to get the event source module without a macro). This is more elegant, abides to "avoid macros" whenever possible :), but will break current API.
  • avoid the case by doing something like: xadhoom@e62bebc

If you like the latter, I can open a PR.

However I like the first idea, I will skip the solution, since it is a use case only for you. But please feel free to create a PR for both solutions, apply PR template. Please explain in both cases what it breaks clearly and how your solution fixes. Please try to ensure that it doesn’t break any current cases.

Well, is not a use case, will happen to anyone that don't error into the yield block, simply the expanded macro code will result into a not used case branch and dialyzer will detect it.

The first one cannot be made without breaking current API, unless we add two new functions. Are you ok with that?

The idea is to enforce to have a error block which prevents wrong data in the event.

Let me try to explain with an example:

You have a topic called: user_created with create_user/1 function and which fails. If you provide the error case, the macro can publish it to the right topic instead of user_created. I believe instead of letting developer not to have an error case, forcing them to the right thing is better.

But maybe it shouldn’t enforce with the error tuple. Still I couldn’t find a better one. I am still trying to understand your solutions and the effects of the solutions. I agree some cases will always return without an error which breaks the contract.

So, better you create PRs and give me time to think. Also EventSource is just a helper module. So, it can be replaced easily using current functions.

When PRs come I will ask help from the community to decide.

Ok, now is more clear (it wasn't from the docs that the error is mandatory for the reasons you have explained, thanks!)

I'll send two PRs and let's see if they makes sense with a wider audience :)

I reopened the issue in favor of your PR

I know this was closed a while ago, but I am still seeing this problem with the latest release, version 1.6.2. So I am not convinced it is fixed.

The following code:

      EventSource.notify %{topic: :subscribe} do
        %{
          topic: topic,
          label: label,
          pid: self(),
          format: format
        }
      end

Gives:

The pattern can never match the type.

Pattern:
{:error, _}

Type:
%{:format => _, :label => _, :pid => pid(), :topic => _}

But I have no need to return an error here.

This appears to be the correct way of sending notifications as per https://github.com/otobus/event_bus/blob/v1.6.2/README.md.