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

Add new syntax, fix credo #18

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open

Conversation

OvermindDL1
Copy link

I do apologize for combining a new syntax PR with an updated Credo PR, but fixing Credo 'as' I was making the new syntax was greatly useful since it stopped the many warnings I was getting on every-full-compile. ^.^;

In addition to the credo warning fixes this adds a new construct named block as well as an auto-raising version of it called block!.

The general pattern of block is like (copied from the docs added for it):

Block

Kind of a combination of Elixir's normal with special form in addition to a monad-style do pipeline.

This automatically-wraps every return value with normalize.

block do
  a <- {:ok, 2}
  b = a * 2
  c <- {:ok, b * 2}
  c * 2
end
#=> 16

block do
  a <- {:ok, 2}
  b = a * 2
  _ = 42
  c <- {:error, "Failed: #{b}"}
  c * 2
end
#=> %ErlangError{original: "Failed: 4"}

conversion_fun = fn
  {:blah, reason} -> %ErlangError{original: "Blah: #{reason}"}
  e -> e
end
block conversion_fun: conversion_fun do
  a <- {:ok, 2}
  b = a * 2
  _ = 42
  c <- {:blah, "Failed: #{b}"}
  c * 2
else
  _ -> {:error, "unknown error"}
end
#=> %ErlangError{original: "unknown error"}

block! do
  a <- {:ok, 2}
  b = a * 2
  _ = 42
  c <- {:error, "Failed: #{b}"}
  c * 2
end
#=> ** (ErlangError) Erlang error: "Failed: 4"

@OvermindDL1
Copy link
Author

Don't merge just yet (if you even want to merge it), this is for discussion at this point.

@OvermindDL1
Copy link
Author

For note, everything should be piecemeal in different commits if you wish to review it more easily.

And for note, I made this because I really hate elixir's normal with special form (nasty comma's ^.^;), plus hey, normalized decomposition! :-)

I guess it might be ready to merge now if you think (and of course, if you want it).

@OvermindDL1
Copy link
Author

I am thinking of adding an option to return a tagged_tuple as well, if so should it be an option or another name for it (block? maybe? I'm not sure about overriding that context though...).

@OvermindDL1
Copy link
Author

Although I guess the user could just pipe it into the tagged tuple maker though...

@OvermindDL1 OvermindDL1 mentioned this pull request Aug 25, 2017
@OvermindDL1
Copy link
Author

What is your thought on adding another expression type of a <~ b that is like <- but auto-wraps in a try/catch?

Also, should I change :non_match = 42 to instead of letting it throw a match exception instead return the non-matched value? That would make it like <- but without the unwrapping/normalization property, which I think might be better (but would make it different from how with acts, which just raises a MatchError too when there is no match on a = call, it only decorates <- calls like I am currently).

Hmm, maybe <~ could be a non-normalization version of <-, or maybe that could be swapped? But if I do that then what would be a good operator for auto-try/catch?

@OvermindDL1
Copy link
Author

Hmm, yeah I'm leaning to having <- be like how with uses it now, just a simple set or return on failed match, and a <~ be a normalized call... Eh... but simplicity is better so perhaps it should remain as it is now... Thoughts? >.>

@expede
Copy link
Owner

expede commented Sep 11, 2017

Woah, didn't see ya there! Looking now 👀

@expede
Copy link
Owner

expede commented Sep 11, 2017

Don't merge just yet (if you even want to merge it), this is for discussion at this point.

You know, I like it! We'll probably see people abusing block do a bit, and wondering where the performance hit is (since the behaviour is so automatic), but my opinion is "with great macros comes great responsibility" 😉

I'm generally a fan. Did you have any specific concerns, @OvermindDL1 ?

{:blah, reason} -> %ErlangError{original: "Blah: #{reason}"}
e -> e
end
block conversion_fun: conversion_fun do
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use the conversion function on occasion so I needed it exposed in at least the base method here. ^.^;

_ = 42
c <- {:blah, "Failed: #{b}"}
c * 2
else
Copy link
Owner

@expede expede Sep 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 Hmm, I wonder if there's a more descriptive word than else here? We have something preeeeetty close to try/rescue here... perhaps rescue, handle, or errors do?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well we can only use an Elixir block keyword if we want it block level here, which I really think we should for consistency with the rest of the language, so rescue is possible, however I was thinking of leaving rescue and catch open for possible exception handling later too, so that really only left things like else and after and so forth, and as with rescue/catch, after also has possible later use with message handling (I've envisioned possible receive block enhancements in this as well later). So if you have any ideas?

end
#=> 16

block do
Copy link
Owner

@expede expede Sep 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a more descriptive term than block? handleable? protected? errorable? Block is very general and could mean anything when reading through the code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was actually paralyzed via Decision Paralysis for a long while so I chose the most simple and descriptive name, even if it is overly generic, and left it up to you if you wanted it changed. ^.^;

I did a search through a variety of libraries though and found it an unused function/macro name surprisingly, so it seemed worth grabbing. :-)

I'd personally think block is overall fine though, it is a generic block that can be enhanced later with far more functionality if it is deemed useful, and renaming it later or having 20 slightly differently named variants for different purposes seems excessive to me. ^.^;

I can rename it though if you wish?

@expede
Copy link
Owner

expede commented Sep 11, 2017

What is your thought on adding another expression type of a <~ b that is like <- but auto-wraps in a try/catch?

I'd maybe name them as separate block types or with options? We should be careful with overloading the tilde operators too much. There's only so many, and we want the code to remain clearish. I already feel bad introducing so many operators and in so many different packages 😬

So yeah, I'd leave the <-, but any change in behaviour could be made an option to let people opt in/out with a sensible default if nothing is specified. Thoughts?

@OvermindDL1
Copy link
Author

OvermindDL1 commented Sep 12, 2017

I'm generally a fan. Did you have any specific concerns, @OvermindDL1 ?

Mostly just what I mentioned above, which is pure usage issues, the code seems sound from my testing. :-)

So yeah, I'd leave the <-, but any change in behaviour could be made an option to let people opt in/out with a sensible default if nothing is specified. Thoughts?

That is what I was leaning to. It is pretty trivial to add more options to the block for more or special functionality and this seems a good, simple, unsurprising, and easy to use base. :-)

@expede
Copy link
Owner

expede commented Dec 19, 2019

This has languished for WAY TOO LONG. I need to dive back into this one; I'll have a but of time soon over the holiday break. Deepest apologies for how long this has taken 🙏

@OvermindDL1
Copy link
Author

I wouldn't be remotely surprised if there were corner cases not caught so a good test suite would be very nice!

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

Successfully merging this pull request may close these issues.

2 participants