-
Notifications
You must be signed in to change notification settings - Fork 147
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
Created subscribe method for Observable spec compatibility #672
Conversation
I'm not opposed to adding interop with RxJS, but I don't want to do it by pretending to be an Observable. Highland streams currently pretend to be a node Even with just this I would much prefer to add a No need to implement it for the 2.x branch. |
Ah hey @vqvu it’s been a few years since we last communicated, I am glad to see you’re still maintaining this project. I respect your dilligence and appreciate your time in thinking through this carefully. This is a too naive an implementation. Additionally, I may have conflated the idea of adding a subscribe method, which I believe is a good interface for consuming values from the streams, with RxJS\Observable compatability. I would like to add support for an observer like object just in case. In the docs we can either mention that it’s a similar approximation or not mention compatability at all like it’s just a regular consumption method as the others. As a happy side effect the subscribe method is compatible with Gulp tasks and if they do switch to the observer object the subscribe method should still support it. I feel this is important as it gives Highland a higher value proposition for Gulp users (I would like to see it become more common), without the code smell of calling toObservable and having to supply an Observable constructor requiring yet another npm dependency. Then lets add a toObservable(Constructor) method as you suggested for official Observable spec compliance. That method should follow the spec tightly so that it works with both Rx and similar implementations. https://tc39.github.io/proposal-observable/ Additionlly, part of the spec proposes a special tagged observable method it looks for when called like It’s implemeneted in Redux already: That should cover the bases of future proofing compatability with Observables and practical usage with today’s tools. What are your thoughts? |
Hi there! I remember you too. It has been a while. I'm still a maintainer. Unfortunately, I don't have the time to make improvements, only bug fixes. That's why 3.0 is still in beta 😅. Thanks for the pointer to the Observable proposal. I wasn't aware of it. I don't have any objections to the I'm happy to accept an implementation for part 3 of that spec. There's no need to implement There's also no need for For the actual implementation, there are a few considerations that I can think of
|
That’s unfortunate to hear highland 3 is stuck in beta, but I have been trying to change my work habits so I do about 20 min - 1.5 hours of sideprojects a day as opposed to larger sprints. I’ve got a couple of small projects lined up for the month but after that I may be able to take a look at what’s left and see if I can contribute. How have you been? I’ve really taken to streams, FRP, and functional programming and have been transitioning into making Clojure my predominant language. Even launched a blog to cover those topics https://eccentric-j.com. Anyway, I was writing a ClojureScript monitoring service the other day and ended up using interop with Highland JS. It worked really well and may write some articles on using highlandjs with gulp and ClojureScript in the next month. That overall sounds like a great plan to me.
|
Coming together so far. Ran out of time to setup the observable\symbol observable behavior 😞 but I should be able to get to that tonight or tomorrow morning. |
I think this is good to go 😄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great. Thanks!
I just have a few minor comments.
I've been good. Can't complain. Good to hear that you're liking streams/FRP. It's such a powerful abstraction. I've never used Clojure seriously before, but I have a friend who does, and he loves it. I think most people use Highland in node, so it's pretty cool to hear that it works in other environments too.
I'd love to have your help if you have the free time. Off the top of my head, what's remaining is
|
Notes:
Anyway this implementation works and the tests pass so it's ready for a review. |
I don't have much experience implementing code to a spec document like this either. However, I think the intent of proposed implementation is to unambiguously specify the expected behavior of the classes. As long as the externally observable behavior is the same, we don't need to replicate it directly. It now occurs to me that you probably created the static
I don't think you need to move the stream consumption code into the |
Will do! I was mentally wrestling with whether it is better to align the interface or both interface and implementation in accordance to the spec. |
Making a push now since I'm not sure the outcome of the nil separation and moving the consume logic. Up to you if you would like to wait until those changes are pushed or discarded, or if you would like to review what should be a pretty stable state. |
PR Comments: - caolan#672 (comment)
Making a push now since I'm not sure the outcome of the nil separation and moving the consume logic. Up to you if you would like to wait until those changes are pushed or discarded, or if you would like to review what should be a pretty stable state. |
This build failed due to an inconsistent return type I introduced into subscribe. Fixed it with |
Better to return a subscriber that is already closed. The caller will not be expecting a Highland stream. |
Requested Changes: - caolan#672 (comment) - caolan#672 (review)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Implemented
.subscribe
method. - Add documentation
- Created tests to ensure the subscribe method performs as expected
- All tests are passing
- Write tests for updated subscriber behavior
- Support observer objects
- Support multiple subscriptions
- Throw error when subscribing to completed stream
- Write test for observable\Symbol.observable behavior
- Implement observable\Symbol.observable behavior
- Write ObservableSubscription tests
- Implement ObservableSubscription class
- All tests are passing
- Instantiate ObservableSubscription with the fork instead of the consume
- Remove create method from ObservableSubscription
- Move ObservableSubscription cleanup into private prototype _cleanup method
- Add .closed check to unsubscribe function to ensure destroy is only called once
- Ensure passing tests
- Return early on consumed subscribe error
- Rename ObservableSubscription.source to _source
- Return closed ObservableSubscription on consumed subscribe error
- Ensure passing tests
- Create nil.js to resolve and export nil value
- Experiment with moving consume logic into ObservableSubscription
- Ensure passing tests
Keep them coming 😄
Also, do you prefer it if I draft solutions and have you review it or would you prefer I ask more questions and discuss options first before implementing? I've been drafting solutions first as I figure it's more concrete but I realized that may be wasting more of your time. |
Whichever one works better for you. It doesn't take me that long to respond to your proposed solution, and having code to comment one is usually easier for me. |
Requested Changes: - caolan#672 (comment) - caolan#672 (comment) - caolan#672 (comment)
|
That process works for me, though there's been a few sloppy mistakes I've let through the cracks and solutions that seemed obvious in your code review I missed in implementation. Perhaps practice will steer my intuition? |
Closing this in favor of #672. |
Context
One of my favorite uses of Highland is with gulpjs:
The combination eliminates like 12 common gulp plugin dependencies.
With the recent release V4 gulp responds to task functions that return an Observable. Looking through the source, it checks for a subscribe function https://github.com/gulpjs/async-done/blob/457ac2aa6fd04fc5620277a8095fa11e8ef61b65/index.js#L72.
This PR adds a subscribe method with the same signature so that gulp will be able to work with highland streams without having to transform into a promise, callback, or node stream.
Usage
Tasks
.subscribe
method.Notes
This was done off the 3x master branch. I'm willing to add it to the 2x branch if desired as well.