How to I make a "select case"-like operation in reactor - project-reactor

I am making a discord bot that needs to read a list of arguments, and with the first argument given, have it determine which branch to run.
Something kinda like this.
Mono.just(stringList)
.ifSelectmap(conditional1, branch1)
.ifSelectmap(conditional2, branch2)
.ifSelectmap(conditional3, branch3)
// non branch logic here
The only way I can figure out to do anything like this would just cause several deeply nested switchIfEmpty statements. Which would be hard to manage.

if the conditional logic doesn't involve latency-heavy operations (ie performing IO), then there is nothing wrong in passing a more fleshed out Function to map/flatMap.
I'm going to assume your "branches" are actually asynchronous operations represented as a Mono<R> or Flux<R> (that is, all the branches share the same return type R), so we're talking flatMap:
Flux<V> source; //...
Flux<R> result = source.flatMap(v -> {
if (conditional1) return branch1(v);
if (conditional2) return branch2(v);
if (conditional3) return branch3(v);
return Mono.empty(); //no conditional match == ignore
//you might want a default processing instead for the above
};

Related

RxJava2 order of sequence called with compleatable andThen operator

I am trying to migrate from RxJava1 to RxJava2. I am replacing all code parts where I previously had Observable<Void> to Compleatable. However I ran into one problem with order of stream calls. When I previously was dealing with Observables and using maps and flatMaps the code worked 'as expected'. However the andthen() operator seems to work a little bit differently. Here is a sample code to simplify the problem itself.
public Single<String> getString() {
Log.d("Starting flow..")
return getCompletable().andThen(getSingle());
}
public Completable getCompletable() {
Log.d("calling getCompletable");
return Completable.create(e -> {
Log.d("doing actuall completable work");
e.onComplete();
}
);
}
public Single<String> getSingle() {
Log.d("calling getSingle");
if(conditionBasedOnActualCompletableWork) {
return getSingleA();
}else{
return getSingleB();
}
}
What I see in the logs in the end is :
1-> Log.d("Starting flow..")
2-> Log.d("calling getCompletable");
3-> Log.d("calling getSingle");
4-> Log.d("doing actuall completable work");
And as you can probably figure out I would expect line 4 to be called before line 3 (afterwards the name of andthen() operator suggest that the code would be called 'after' Completable finishes it's job). Previously I was creating the Observable<Void> using the Async.toAsync() operator and the method which is now called getSingle was in flatMap stream - it worked like I expected it to, so Log 4 would appear before 3. Now I tried changing the way the Compleatable is created - like using fromAction or fromCallable but it behaves the same. I also couldn't find any other operator to replace andthen(). To underline - the method must be a Completable since it doesn't have any thing meaning full to return - it changes the app preferences and other settings (and is used like that globally mostly working 'as expected') and those changes are needed later in the stream. I also tried to wrap getSingle() method to somehow create a Single and move the if statement inside the create block but I don't know how to use getSingleA/B() methods inside there. And I need to use them as they have their complexity of their own and it doesn't make sense to duplicate the code. Any one have any idea how to modify this in RxJava2 so it behaves the same? There are multiple places where I rely on a Compleatable job to finish before moving forward with the stream (like refreshing session token, updating db, preferences etc. - no problem in RxJava1 using flatMap).
You can use defer:
getCompletable().andThen(Single.defer(() -> getSingle()))
That way, you don't execute the contents of getSingle() immediately but only when the Completablecompletes and andThen switches to the Single.

Caching streams in Functional Reactive Programming

I have an application which is written entirely using the FRP paradigm and I think I am having performance issues due to the way that I am creating the streams. It is written in Haxe but the problem is not language specific.
For example, I have this function which returns a stream that resolves every time a config file is updated for that specific section like the following:
function getConfigSection(section:String) : Stream<Map<String, String>> {
return configFileUpdated()
.then(filterForSectionChanged(section))
.then(readFile)
.then(parseYaml);
}
In the reactive programming library I am using called promhx each step of the chain should remember its last resolved value but I think every time I call this function I am recreating the stream and reprocessing each step. This is a problem with the way I am using it rather than the library.
Since this function is called everywhere parsing the YAML every time it is needed is killing the performance and is taking up over 50% of the CPU time according to profiling.
As a fix I have done something like the following using a Map stored as an instance variable that caches the streams:
function getConfigSection(section:String) : Stream<Map<String, String>> {
var cachedStream = this._streamCache.get(section);
if (cachedStream != null) {
return cachedStream;
}
var stream = configFileUpdated()
.filter(sectionFilter(section))
.then(readFile)
.then(parseYaml);
this._streamCache.set(section, stream);
return stream;
}
This might be a good solution to the problem but it doesn't feel right to me. I am wondering if anyone can think of a cleaner solution that maybe uses a more functional approach (closures etc.) or even an extension I can add to the stream like a cache function.
Another way I could do it is to create the streams before hand and store them in fields that can be accessed by consumers. I don't like this approach because I don't want to make a field for every config section, I like being able to call a function with a specific section and get a stream back.
I'd love any ideas that could give me a fresh perspective!
Well, I think one answer is to just abstract away the caching like so:
class Test {
static function main() {
var sideeffects = 0;
var cached = memoize(function (x) return x + sideeffects++);
cached(1);
trace(sideeffects);//1
cached(1);
trace(sideeffects);//1
cached(3);
trace(sideeffects);//2
cached(3);
trace(sideeffects);//2
}
#:generic static function memoize<In, Out>(f:In->Out):In->Out {
var m = new Map<In, Out>();
return
function (input:In)
return switch m[input] {
case null: m[input] = f(input);
case output: output;
}
}
}
You may be able to find a more "functional" implementation for memoize down the road. But the important thing is that it is a separate thing now and you can use it at will.
You may choose to memoize(parseYaml) so that toggling two states in the file actually becomes very cheap after both have been parsed once. You can also tweak memoize to manage the cache size according to whatever strategy proves the most valuable.

ANTLR Parse tree modification

I'm using ANTLR4 to create a parse tree for my grammar, what I want to do is modify certain nodes in the tree. This will include removing certain nodes and inserting new ones. The purpose behind this is optimization for the language I am writing. I have yet to find a solution to this problem. What would be the best way to go about this?
While there is currently no real support or tools for tree rewriting, it is very possible to do. It's not even that painful.
The ParseTreeListener or your MyBaseListener can be used with a ParseTreeWalker to walk your parse tree.
From here, you can remove nodes with ParserRuleContext.removeLastChild(), however when doing this, you have to watch out for ParseTreeWalker.walk:
public void walk(ParseTreeListener listener, ParseTree t) {
if ( t instanceof ErrorNode) {
listener.visitErrorNode((ErrorNode)t);
return;
}
else if ( t instanceof TerminalNode) {
listener.visitTerminal((TerminalNode)t);
return;
}
RuleNode r = (RuleNode)t;
enterRule(listener, r);
int n = r.getChildCount();
for (int i = 0; i<n; i++) {
walk(listener, r.getChild(i));
}
exitRule(listener, r);
}
You must replace removed nodes with something if the walker has visited parents of those nodes, I usually pick empty ParseRuleContext objects (this is because of the cached value of n in the method above). This prevents the ParseTreeWalker from throwing a NPE.
When adding nodes, make sure to set the mutable parent on the ParseRuleContext to the new parent. Also, because of the cached n in the method above, a good strategy is to detect where the changes need to be before you hit where you want your changes to go in the walk, so the ParseTreeWalker will walk over them in the same pass (other wise you might need multiple passes...)
Your pseudo code should look like this:
public void enterRewriteTarget(#NotNull MyParser.RewriteTargetContext ctx){
if(shouldRewrite(ctx)){
ArrayList<ParseTree> nodesReplaced = replaceNodes(ctx);
addChildTo(ctx, createNewParentFor(nodesReplaced));
}
}
I've used this method to write a transpiler that compiled a synchronous internal language into asynchronous javascript. It was pretty painful.
Another approach would be to write a ParseTreeVisitor that converts the tree back to a string. (This can be trivial in some cases, because you are only calling TerminalNode.getText() and concatenate in aggregateResult(..).)
You then add the modifications to this visitor so that the resulting string representation contains the modifications you try to achieve.
Then parse the string and you get a parse tree with the desired modifications.
This is certainly hackish in some ways, since you parse the string twice. On the other hand the solution does not rely on antlr implementation details.
I needed something similar for simple transformations. I ended up using a ParseTreeWalker and a custom ...BaseListener where I overwrote the enter... methods. Inside this method the ParserRuleContext.children is available and can be manipulated.
class MyListener extends ...BaseListener {
#Override
public void enter...(...Context ctx) {
super.enter...(ctx);
ctx.children.add(...);
}
}
new ParseTreeWalker().walk(new MyListener(), parseTree);

Exiting from the middle of a drools rule

In java method we can return from the middle skipping the rest of the method code being executed. e.g.
public String doSomething(){
step 1
step 2
if(some condition){
return "Exited from the middle";
}
step 4
return "Whole code is executed"
}
Is there a way to do such things in a drools rule?
It's quite simple:
return;
Since there's no place of invocation for a single rule you can control, or write code doing that, a return with an expression is not vailable. You can collect values you'd like to return in a global variable, List<String> or, perhaps, Map<String,List<String>> with rule names acting as keys.
Clarification
A rule's right hand side results in a static method with void as result type. A return statement just acts naturally.

Executing my 3 calls one after the other in my activate function

I work on a project with durandal/breeze. I have the following code in my activate function:
var activate = function (routeData) {
initLookups();
var idTran = parseInt(routeData.idTran);
var idItin = parseInt(routeData.idItin);
if (idItin == -1)
idItin = datacontext.createItineraryDetailTransport(idTran);
datacontext.getTransportById(idTran, transport);
datacontext.getItineraryById(idItin, itinerary);
}
As you can see in the above code, I have 3 calls to the datacontext:
datacontext.createItineraryDetailTransport >> eventually... if (idItin == -1)
datacontext.getTransportById
datacontext.getItineraryById
The problem right now is that each call is not waiting for the previous one to complete before executing.
My question: how to proceed to be sure one call is finished before executing the next one? Please note that the first call is inside a condition... I'm thinking of using 'promises' but don't know.
Thanks.
The tricky part to what you're trying to do is conditionally chain three calls together.
You can simply chain multiple calls together using the then() method. However in your case, you need an initial promise to chain when the first condition isn't met.
The $.when() method is the trick here, because you can either chain an promise returned by Breeze, or you can chain a "dummy" promise, which is what $.when() gives you. If the first parameter passed to $.when is not a promise, then it returns a promise that is immediately resolved.
If I understand your question correctly, you should be able to write your code something like this:
var activate = function (routeData) {
initLookups();
var idTran = parseInt(routeData.idTran);
var idItin = parseInt(routeData.idItin);
var idtDeferred = $.when();
if (idItin == -1)
idtDeferred = datacontext.createItineraryDetailTransport(idTran);
idtDeferred
.then(datacontext.getTransportById(idTran, transport))
.then(datacontext.getItineraryById(idItin, itinerary));
}
Your code example looks like datacontext.createItineraryDetailTransport is supposed to set the idItin var, but I'm assuming that it returns a promise like typical breeze queries.
Certain parts of your example are unclear to me.
Is initLookups asynchronous? If so, do you have to wait for it to complete before performing the other asynchronous steps?
How can createItineraryDetailTransport be asynchronous when it returns the integer, idItin?
What the heck does createItineraryDetailTransport actually do? My guess is that idItin == -1 when you don't have an ItineraryDetailTransport entity yet and therefore don't have the key you need to call getItineraryById. If so, you have to restructure the signature of createItineraryDetailTransport.
Why does getItineraryById have to wait for getTransportById when they seemingly have nothing in common?
What are transport and itinerary? I'm guessing they are accidentally omitted variables that will be set with the results of the async calls within those datacontext methods.
Where is your error handling? What should happen if one of the async calls fails?
These issues must be sorted out before someone can give you a really good answer.
Joseph Gabriel seems to me to be mostly on the right track although I might have written it a little differently
...
var transport, itinerary;
var promise = (idItin == -1) ?
datacontext.createItineraryDetailTransport(aCallBackThatSets_idItin) :
Q.resolve(); // creates a resolved promise
promise = promise
.then(datacontext.getTransportById(idTran, transport)
.then(datacontext.getItineraryById(idItin, itinerary))
.fail(yourErrorHandler);
return promise; // don't forget to return the promise!
The most important step missing from Joseph Gabriel's suggestion ... and the reason you couldn't make his suggestion work ... is that it neglected to return the promise.
You must return a promise if you want Durandal to wait before activating the view.

Resources