NullOranje
Yaq - An Enumerable Queue for Elixir
While working on a work project, I found I needed a more Elixir-like queue versus the Erlang :queue module. So I decided to write one. I liked what I did, so I’m sharing it with others.
Yaq (Yet another queue) is a double-ended queue that supports both the Enumerable and Collectable protocols. I wanted something I could use with the pipe operator, since with my use case I found myself having to write a lot of functions to make :queue work correctly.
This is my first library I’m sharing with the community. I not only wanted a library I could use in my day job, but something I could take an opportunity to learn how to “do things right” so with regards to Elixir.
Source code is available on Github: https://github.com/NullOranje/yaq
Hex package: https://hex.pm/packages/yaq
Documentation: https://hexdocs.pm/yaq/api-reference.html
Any and all feedback is welcome.
Most Liked
kip
NobbZ
I really should try polishing this ![]()
NobbZ
I get a 404 for the GitHub repository.
Also from the examples in the documentation, I really do not like that its inspection shows the length of the queue but not the contents…
Oh, and I just realise, Yaq.value/0 is nil | term, term includes nil, so why is nil mentioned extra here?
Why is there no Yaq.t/1 which would allow us to specify the members types as well?
NobbZ
nil is just an atom, specialcased by the parser to be able to leave off the colon.
In my opinion having marker or value is deemed to fail anyway. What if is I want to insert exactly the value you use as marker?
Please use a tagged tuple or at least provide an API similar to Map get/fetch/fetch! to be able to differentiate when necessary.
Also when you say, it’s collectable and enumerable, in which direction? Is there a way to collect/enumerate in the opposite direction?
NullOranje
I’ve had this same though about using atoms as markers. It’s a pretty common pattern in Erlang/OTP from what I can see, but the scenario you describe seems likely, especially when using common atoms like :ok (or nil).
I liked your suggestion about following the get/fetch/fetch! paradigm in Map and elsewhere, so I added a couple functions to the API:
fetch/1andfetch_r/1will return the tuple{value, updated_queue}if there are elements on the front or back of the queue, respectively, or:errorotherwisefetch!/1andfetch_r!/1will return the tuple{value, updated_queue}if there are elements on the front or back of the queue, respectively, or raiseYaq.EmptyQueueErrorotherwise
I also added a default value specification for dequeue/2 and dequeue_r/2 to follow the pattern from get.
You can only enumerate and collect from front to back, but you can reverse the queue in constant time with Yak.reverse/1, so I think it is a fair compromise.








