Optional arguments for higher-order functions - interop

I try to write a binding for socket.io.
I am having trouble with a function (next() in my example code at the bottom), that either takes no argument or a error object (Js.Exn.raiseError("ERROR!")).
I can't find a way to define a function signature that can take both types of argument as the first value.
I am not even sure, if what I am asking for is possible in rescript, any help to solve that problem in the proper rescript way, would be appreciated.
My current implementation looks like this:
type server
type socket
type next = (. unit) => unit
#new #module("socket.io") external socketIO: unit => server = "Server"
#send external use: (server, (socket, next) => unit) => unit = "use"
#send external listen: (server, int) => unit = "listen"
#send external on: (server, #string [ #connection(socket => unit) ] ) => unit = "on"
let io = socketIO()
io->use((socket, next) => {
Js.log("FIRST")
next(.)
})
io->use((socket, next) => {
Js.log("SECOND")
next(.)
})
io->on(#connection(socket =>
Js.log("CONNECT")
))
io->listen(3000)

It's not possible in general to have a function with a variable number of arguments, but it is possible to pass either undefined or a value, which in most cases will be equivalent.
One way to do so is to simply use the option type. If we re-define next as
type next = (. option<int>) => unit
we can use it like this
io->use((_socket, next) => {
next(. None)
next(. Some(42))
})
which will generate the following JavaScript:
io.use(function (_socket, next) {
next(undefined);
return next(42);
});
Another option could be to use optional arguments, but this doesn't seem to work with uncurrying, and recently there's been bugs with currying that the compiler author seems to have no interest in fixing, so it might not work there either, but it might be worth a shot:
type next = (~error: int=?, unit) => unit
...
io->use((_socket, next) => {
next(())
next(~error=42, ())
})
Lastly, there already exists some bindings for socket.io (bs-socket.io). These also don't handle this case unfortunately, but it might save you from re-inventing some wheels at least.

Related

Is it bad to use a variable from outside the observable pipe within an operator?

Is using a variable from outside an observable within an operator considered a (significantly) bad practice?
createObservableExample1(parameter1: string, obs$: Observable<string>): Observable<string> {
return obs$.pipe(
map( x => {
const returnValue = `${parameter1}, ${x}`;
return returnValue;
})
);
}
I understand you can do something like this:
createObservableExample2(parameter1: string, obs$: Observable<string>): Observable<string> {
return combineLatest([
of(parameter1),
obs$
]).pipe(
map( (x, y) => {
const returnValue = `${x}, ${y}`;
return returnValue;
})
);
}
But is it worth it?
Does this just come down to accessing variables from outside the scope of anonymous function? Would this force the context of the enclosing method to exist for longer than it should? I remember a code tool I used to use for C# complaining about something similar to this. I have found somewhat related topics by searching for, "anonymous functions and closures", but as of yet, nothing really discussing the scenario explained above.
I ask because I have been creating some relatively complex observables that have enormous operator chains, and constantly adding the needed variables, using combineLatest and of, from the parent scope can make the code even harder to follow.
When I teach Reactive programming to neophytes, I try to make them grasp : Do not break the reactivity by having uneccessary side effects :
no input that from a state (for example using a class or instance property
no storing outside value.
There is none of these red flags in your example. Your function is pure & idempotent with both implementation, go with what ever you like and if possible be consistant within your code base !

RxJS iif arguments are called when shouldn't

I want to conditionally dispatch some actions using iif utility from RxJS. The problem is that second argument to iif is called even if test function returns false. This throws an error and app crashes immediately. I am new to to the power of RxJS so i probably don't know something. And i am using connected-react-router package if that matters.
export const roomRouteEpic: Epic = (action$, state$) =>
action$.ofType(LOCATION_CHANGE).pipe(
pluck('payload'),
mergeMap(payload =>
iif(
() => {
console.log('NOT LOGGED');
return /^\/room\/\d+$/.test(payload.location.pathname); // set as '/login'
},
merge(
tap(v => console.log('NOT LOGGED TOO')),
of(
// following state value is immediately evaluated
state$.value.rooms.list[payload.location.pathname.split('/')[1]]
? actions.rooms.initRoomEnter()
: actions.rooms.initRoomCreate(),
),
of(actions.global.setIsLoading(true)),
),
empty(),
),
),
);
A little late to the party, but I found that the role of iif is not to execute one path over the other, but to subscribe to one Observable or the other. That said, it will execute any and all code paths required to get each Observable.
From this example...
import { iif, of, pipe } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
const source$ = of('Hello');
const obsOne$ = (x) => {console.log(`${x} World`); return of('One')};
const obsTwo$ = (x) => {console.log(`${x}, Goodbye`); return of('Two')};
source$.pipe(
mergeMap(v =>
iif(
() => v === 'Hello',
obsOne$(v),
obsTwo$(v)
))
).subscribe(console.log);
you'll get the following output
Hello World
Hello, Goodbye
One
This is because, in order to get obsOne$ it needed to print Hello World. The same is true for obsTwo$ (except that path prints Hello, Goodbye).
However you'll notice that it only prints One and not Two. This is because iif evaluated to true, thus subscribing to obsOne$.
While your ternary works - I found this article explains a more RxJS driven way of achieving your desired outcome quite nicely: https://rangle.io/blog/rxjs-where-is-the-if-else-operator/
Ok, i found an answer on my own. My solution is to remove iif completely and rely on just ternary operator inside mergeMap. that way its not evaluated after every 'LOCATION_CHANGE' and just if regExp returns true. Thanks for your interest.
export const roomRouteEpic: Epic = (action$, state$) =>
action$.ofType(LOCATION_CHANGE).pipe(
pluck<any, any>('payload'),
mergeMap(payload =>
/^\/room\/\d+$/.test(payload.location.pathname)
? of(
state$.value.rooms.list[payload.location.pathname.split('/')[2]]
? actions.rooms.initRoomEnter()
: actions.rooms.initRoomCreate(),
actions.global.setIsLoading(true),
)
: EMPTY,
),
);
If you use tap operator inside observable creation(because it returns void), it will cause error as below
Error: You provided 'function tapOperatorFunction(source) {
return source.lift(new DoOperator(nextOrObserver, error, complete));
}' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
Remove the tap and put the console in the subscribe().
I have created a stackblitz demo.
Another consideration is that even though Observables and Promises can be used in the same context many times when working with RxJS, their behavior will be different when dealing with iif. As mentioned above, iif conditionally subscribes; it doesn't conditionally execute. I had something like this:
.pipe(
mergeMap((input) =>
iif(() => condition,
functionReturningAPromise(input), // A Promise!
of(null)
)
)
)
This was evaluating the Promise-returning function regardless of the condition because Promises don't need to be subscribed to to run. I fixed it by switching to an if statement (a ternary would have worked as well).

Binding to ReactiveCommand.IsExecuting

I'm would like to know the recommended way to bind to ReactiveCommand's IsExecuting.
The problem is the initial command execution (started at the end of the constructor) is not updating the WPF control using IsLoading as a binding, although subsequent calls work as expected.
Update 2 Add test binding code
This shows the adorner content when IsLoading is true
<ac:AdornedControl IsAdornerVisible="{Binding IsLoading}">
<ac:AdornedControl.AdornerContent>
<controls1:LoadingAdornerContent/>
</ac:AdornedControl.AdornerContent>
<fluent:ComboBox
ItemsSource="{Binding Content, Mode=OneWay}"
DisplayMemberPath="Name"
SelectedValuePath="ContentId"
SelectedValue="{Binding SelectedContentId}"
IsSynchronizedWithCurrentItem="True"
/>
</ac:AdornedControl>
Update
I found this:
https://github.com/reactiveui/rxui-design-guidelines
and figured I should be able to do something like:
this._isLoading = this.WhenAnyValue(x => x.LoadCommand.IsExecuting)
.ToProperty(this, x => x.IsLoading);
but it gives the compilation error:
The type arguments for method
'ReactiveUI.OAPHCreationHelperMixin.ToProperty<
TObj,TRet>(System.IObservable< TRet>, TObj,
System.Linq.Expressions.Expression< System.Func< TObj,TRet>>, TRet,
System.Reactive.Concurrency.IScheduler)' cannot be inferred from the
usage. Try specifying the type arguments explicitly.
I also tried:
this._isLoading = this.WhenAnyValue(x => x.LoadCommand.IsExecuting)
.ToProperty<TheViewModel, bool>(this, x => x.IsLoading);
but get the compilation error:
'System.IObservable< System.IObservable< bool >>' does not contain a
definition for 'ToProperty' and the best extension method overload
'ReactiveUI.OAPHCreationHelperMixin.ToProperty<
TObj,TRet>(System.IObservable< TRet>, TObj,
System.Linq.Expressions.Expression< System.Func< TObj,TRet>>, TRet,
System.Reactive.Concurrency.IScheduler)' has some invalid arguments
and
Instance argument: cannot convert from
'System.IObservable>' to
'System.IObservable'
Original Below
The code listed at the end of my post works for the initial bind by accessing the IsLoading property and it sounds like that kicks off a subscription. But from further reading it seems I should be using WhenAny and I can't seem to figure out what has been put in front of my nose:
ToProperty and BindTo - Get initial value without Subscribing
Adding:
this.WhenAnyValue(x => x.LoadCommand.IsExecuting);
also works, but is there a better way?
I was thinking removing the ObservableAsPropertyHelper as it doesn't seem to be doing much for me and making IsLoading a normal property like:
private bool _isLoading;
public bool IsLoading
{
get { return _isLoading; }
set { this.RaiseAndSetIfChanged(ref _isLoading, value); }
}
And doing something like the following, but it doesn't compile because it is trying to assign a IObservable< bool> to a bool:
this.WhenAnyValue(x => x.LoadCommand.IsExecuting)
.Subscribe(x => IsLoading = x);
Current code:
private readonly ObservableAsPropertyHelper<bool> _isLoading;
public bool IsLoading
{
get { return _isLoading.Value; }
}
LoadCommand = ReactiveCommand.CreateAsyncTask(async _ =>
{
//go do command stuff like fetch data from a database
}
LoadCommand.IsExecuting.ToProperty(this, x => x.IsLoading, out _isLoading);
//works if I have this line
var startSubscription = IsLoading;
LoadCommand.ExecuteAsyncTask();
and figured I should be able to do something like:
You've got the right idea, but the syntax is a bit off, try:
this.LoadCommand.IsExecuting
.ToProperty(this, x => x.IsLoading, out _isLoading);
If you were to do this with objects that can change (i.e. you've got a long expression), there's a special method called WhenAnyObservable that you use instead of WhenAnyValue:
this.WhenAnyObservable(x => x.SomeObjectThatMightBeReplaced.IsExecuting)
.ToProperty(this, x => x.IsLoading, out _isLoading);
I have run into this before and I think what you are experiencing lies here.
ToProperty / OAPH changes
ObservableAsPropertyHelper no longer is itself an IObservable, use WhenAny to observe it.
ObservableAsPropertyHelper now lazily Subscribes to the source only when the Value is read for the first time. This significantly improves performance and memory usage, but at the cost of some "Why doesn't my test work??" confusion. If you find that your ToProperty "isn't working", this may be why.
It is lazy, so you must subscribe to it (i.e. request a value from the property if using OAPH) for it to work. That is why you notice that your var startSubscription = IsLoading; 'fixes' the issue.
Knowing that made it easier for me to determine whether or not this was even an issue, or just something to keep in mind during my unit tests, knowing that in my application these properties would be bound to and hence subscribed to, making it moot in practice. You know, the whole "tree falling in the forest with no one there to hear it" idea.
I think you should stick with the ToProperty that you have, that seems the way to go IMHO.

What does it mean to pass `_` (i.e., underscore) as the sole parameter to a Dart language function?

I'm learning Dart and see the following idiom a lot:
someFuture.then((_) => someFunc());
I have also seen code like:
someOtherFuture.then(() => someOtherFunc());
Is there a functional difference between these two examples?
A.k.a., What does passing _ as a parameter to a Dart function do?
This is particularly confusing given Dart's use of _ as a prefix for declaring private functions.
It's a variable named _ typically because you plan to not use it and throw it away. For example you can use the name x or foo instead.
The difference between (_) and () is simple in that one function takes an argument and the other doesn't.
DON’T use a leading underscore for identifiers that aren’t private.
Exception: An unused parameter can be named _, __, ___, etc. This
happens in things like callbacks where you are passed a value but you
don’t need to use it. Giving it a name that consists solely of
underscores is the idiomatic way to indicate the value isn’t used.
https://dart.dev/guides/language/effective-dart/style
An underscore (_) is usually an indication that you will not be using this parameter within the block. This is just a neat way to write code.
Let's say I've a method with two parameters useful and useless and I'm not using useless in the code block:
void method(int useful, int useless) {
print(useful);
}
Since useless variable won't be used, I should rather write the above code as:
void method(int useful, int _) { // 'useless' is replaced with '_'
print(useful);
}
From the Dart Doc - PREFER using _, __, etc. for unused callback parameters.
Sometimes the type signature of a callback function requires a
parameter, but the callback implementation doesn't use the
parameter. In this case, it's idiomatic to name the unused parameter
_. If the function has multiple unused parameters, use additional
underscores to avoid name collisions: __, ___, etc.
futureOfVoid.then((_) {
print('Operation complete.');
});
This guideline is only for functions that are both anonymous and
local. These functions are usually used immediately in a context
where it's clear what the unused parameter represents. In contrast,
top-level functions and method declarations don't have that context,
so their parameters must be named so that it's clear what each
parameter is for, even if it isn't used.
Copy paste the following code in DartPad and hit Run -
void main() {
Future.delayed(Duration(seconds: 1), () {
print("No argument Anonymous function");
});
funcReturnsInteger().then((_) {
print("Single argument Anonymous function " +
"stating not interested in using argument " +
"but can be accessed like this -> $_");
});
}
Future<int> funcReturnsInteger() async {
return 100;
}
That expression is similar to "callbacks" in node.js, the expression have relation to async task.
First remember that => expr expression is shorthand for {return *expr*}, now in someFuture.then((_) => someFunc()), someFuture is a variable of type Future, and this keeps your async task, with the .then method you tell what to do with your async task (once completed), and args in this method you put the callback ((response) => doSomethingWith(response)).
You learn more at Future-Based APIs and Functions in Dart. Thanks
Very common use, is when we need to push a new route with Navigator but the context variable in the builder is not going to be used:
// context is going to be used
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => NewPage(),
));
// context is NOT going to be used
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => NewPage(),
));
I think what people are confusing here is that many think the _ in
someFuture.then((_) => someFunc());
is a parameter provided to the callback function which is wrong, its actually a parameter passed back from the function that you can give a name that you want (except reserved keywords of course), in this case its an underscore to show that the parameter will not be used. otherwise, you could do something like in example given above:((response) => doSomethingWith(response))

Liftable for function literal

Is there a way to make a Liftable for a functional literal (with 2.11)? If I have
case class Validator[T](predicate: T => Boolean)
val predicate = (s: String) => s.startsWith("Hi")
then I want to be able to quasiquote predicate too:
q"new Validator($predicate)"
I hoped to magically create a Liftable with an underscore. But that was a little too optimistic:
implicit def liftPredicate[T: Liftable](f: T => Boolean) =
Liftable[T => Boolean]{ f => q"$f(_)" }
I couldn't figure out from looking at StandardLiftables how I could solve this one.
Another way of looking at it:
Say I want to create instances from the following class at compile time with a macro:
abstract class ClassWithValidation {
val predicate: String => Boolean
def validate(s: String) = predicate(s)
}
and I retrieve a functional literal from somewhere else as a variable value:
val predicate = (s: String) => s.startsWith("Hi")
Then I want to simply quasiquote that variable into the construction:
q"""new ClassWithValidation {
val predicate = $predicate
// other stuff...
}"""
But it gives me this error:
Error:(46, 28) Can't unquote String => Boolean, consider providing an
implicit instance of Liftable[String => Boolean]
Normally I can just make such implicit Liftable for a custom type. But I haven't found a way doing the same for a functional literal. Is there a way to do this or do I need to look at it another way?
From what I understand, you're trying to go from a function to an abstract syntax tree that represents its source code (so that it can be spliced into a macro expansion). This is a frequent thing that people request (e.g. it comes up often in DSLs), but there's no straightforward way of achieving that in our current macro system.
What you can do about this at the moment is to save the AST explicitly when declaring a function and then load and use it in your macro. The most convenient way of doing this is via another macro: https://gist.github.com/xeno-by/4542402. One could also imagine writing a macro annotation that would work along the same lines.
In Project Palladium, there is a plan to save typechecked trees for every program being compiled. This means that there will most likely be a straightforward API, e.g. treeOf(predicate) that would automatically return abstract syntax tree comprising the source of the predicate. But that's definitely not something set in stone - we'll see how it goes, and I'll report back on the progress during this year's ScalaDays.

Resources