Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to return values from a result block #5

Closed
CrowdHailer opened this issue Dec 12, 2016 · 5 comments
Closed

How to return values from a result block #5

CrowdHailer opened this issue Dec 12, 2016 · 5 comments

Comments

@CrowdHailer
Copy link
Owner

Take the following example, which is available in the test suite

OK.try do
  a <- safe_div(8, 2)
  b <- safe_div(a, 2)
  _ <- {:ok, a + b}
end

Wrapping the result in an ok tuple and matching it to a throw away variable is noise, that I would like to remove.

Currently replacing the last line with the following alternative will error.

OK.try do
  ...
  a + b
end

This is probably the correct behaviour, if we allow the above we have to assume the last line is a success. One alternative is to assume the last line always returns a result tuple. Then the last line can be simplified to

OK.try do
  ...
  success(a + b)
  failure(:reason)
end

A more advanced option would be to add a yield block.

OK.try do
  ...
  yield
  a + b
end

The problem with this is that yield is not a keyword like else to try/yield/end will not look the same as if/else/end.
Could use else as the start of the yield block, messy if we ever decide to use else for some error handling.
Could see if there is a way to add yield or another keyword to behave the same way as else

@CrowdHailer
Copy link
Owner Author

The most natural answer is just to return the final line.

Not asserting that this is a result tuple allows the following use cases.

OK.for do
  data <- SignupForm.validate(form)
  customer <- MyApp.signup(data)
  Response.ok(welcome_page(customer))
rescue
  form_with_errors in InvalidForm ->
    Response.bad_request(signup_page(form_with_errors))
  error in EmailConflict ->
    Response.conflict(signup_page(form))
end

@CrowdHailer
Copy link
Owner Author

CrowdHailer commented Mar 30, 2017

Currently we assert that the last line is a result tuple. I am thinking of dropping this requirement.
Users can add a bind expression to the last line of a block to ensure correct behaviour.

OK.with do
  # stuff
  _ <- foo() # foo must return {:ok, v} or {:error, reason}
end

OR just have the last line clearly show intent

OK.with do
  # stuff
  x <- foo() 
  OK.success(x)
end
OK.with do
  # stuff
  foo() # foo can return anything
end

@ghost
Copy link

ghost commented Apr 4, 2017

This would enable easier integration with Phoenix channels that expect a reply tuple. I already ran into this and was able to work around it, but I think it makes sense, if at the very least pragmatically. 👍

@CrowdHailer
Copy link
Owner Author

What was the work around? @bill-mybiz

@ghost
Copy link

ghost commented Apr 4, 2017

@CrowdHailer I changed my command pattern implementations to all return ok/error tuples and wrapped those in the reply tuple at the command handler entry point. Ended up being cleaner, since the commands themselves now know nothing of the Phoenix implementation details. Also it is DRYer because there is only the one reference to the reply tuple instead of n references. (n being the number of commands implemented).

Before:
https://github.com/ibgib/ibgib/blob/v0.2.3/ib_gib_umb/apps/web_gib/lib/web_gib/bus/commanding.ex#L16

After:
https://github.com/ibgib/ibgib/blob/v0.3.0/ib_gib_umb/apps/web_gib/lib/web_gib/bus/commanding.ex#L16

There is also a try...rescue added (my first in Elixir hah, crazy language) because I found channel commands absolutely should not fail fast when a reply is expected 😆

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant