How to do chained callbacks in F#? - f#

In C# I am using the asynchronous versions of TcpListener/TcpClient, and I am chaining these via the callback method so that another Accept/Read is posted when the callback completes. Here is an example (untested):
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 3000);
listener.Start();
PostAccept(listener);
}
private void PostAccept(TcpListener listener)
{
listener.BeginAcceptTcpClient(AcceptCallback, listener);
}
private void AcceptCallback(IAsyncResult ar)
{
var listener = ar.AsyncState as TcpListener;
if (listener == null)
{
return;
}
// get the TcpClient and begin a read chain in a similar manner
PostAccept(listener);
}
My question is how do I model something similar in F#? Would I use the async keyword? Is the code after BeginAcceptTcpClient, BeginRead, etc.. essentially the code that would be executed in the callback function? For example, is this correct?
let accept(listener:TcpListener) = async {
let! client = listener.AsyncAcceptTcpClient()
// do something with the TcpClient such as beginning a Read chain
accept(listener)
return()
}
The above code doesn't work because accept isn't defined, and marking it recursive technically isn't true as it isn't a recursive method?

#kvb's answer is correct and idiomatic.
Just wanted to also point out you can use (gasp) a loop:
let accept(t:TcpListener) =
let completed = ref false
async {
while not(!completed) do
let! client = t.AsyncAcceptTcpClient()
if client <> null then
Blah(client)
else
completed := true
}
(that was typing code into my browser, hopefully it compiles). Which is nice, since you certainly can't use a loop in the C# code (that has to span multiple methods with the begin/end callbacks).

I'm not sure what you mean by "it isn't a recusive method"; if you refer to a function from within its own definition, then it is a recursive function. I don't have much experience with the Sockets classes, but perhaps something along these lines is what you're looking for?
let rec accept(t : TcpListener) =
async {
let! client = t.AsyncAcceptTcpClient()
// do some stuff with client here
do! accept(t)
}

Related

How to handle streams and transactions with java-grpc

I'm having an issue with gRPC streaming in Java but I believe this problem also exists in other "reactive" contexts.
If you have a method like this (Kotlin):
#Transactional
override fun get(
request: DummyRequest,
responseObserver: StreamObserver<DummyResponse>,
) {
val counter = AtomicInteger()
myStreamingDatabaseQuery().use {
it.iterator().forEach { responseObserver.onNext(it) }
}
responseObserver.onCompleted()
}
fun myStreamingDatabaseQuery(): Stream<Dummy> = ...
It will work fine as the transaction is opened, the stream is processed and closed, and then thetransaction is closed.
However, you might then run into memory issues and try to use some sort of flow control like this:
#Transactional
override fun get(
request: DummyRequest,
responseObserver: StreamObserver<DummyResponse>,
) {
val counter = AtomicInteger()
val iterator = myStreamingDatabaseQuery().iterator()
StreamObservers.copyWithFlowControl(
iterator,
responseObserver as CallStreamObserver<DummyResponse>,
)
}
fun myStreamingDatabaseQuery(): Stream<Dummy> = ...
This won't work because StreamObservers just sets an onReadyHandler and immediately returns. The stream will then be processed in this handler, after get() has returned - and therefore the transaction will have been closed and it can no longer read the stream.
How is this commonly solved? And how would I do it with grpc-java/Spring?

Using Swift Task inside a flatmap for async/await

I'm trying to receive an async function return value inside a flatMap and wrap it under a Task to allow for async functionality but I'm having this error when I'm trying to access the Task value:
'async' property access in a function that does not support concurrency
How do I go about returning the value?
Playground
import UIKit
public func isEvenNumber(num:(Int)) async -> Result<Int, Error> {
if num%2 == 0 {
print("EVEN")
return .success(1)
}
print("ODD")
return .success(0)
}
func profileAsyncFunc() async -> Result<Bool, Error> {
return await isEvenNumber(num: 3)
.flatMap{ _ -> Result<Bool,Error> in
Task {
return await testAsyncFunc()
}.value
}
}
func testAsyncFunc() async -> Result<Bool, Error> {
let basicTask = Task { () -> Result<Bool, Error> in
.success(true)
}
return await basicTask.value
}
Task {
await profileAsyncFunc()
}
A few observations:
Swift concurrency simplifies this quite a bit. No flatMap is needed.
The isEvenNumber is not really asynchronous unless you await something. Adding async qualifier does not make it asynchronous. It only means that you could add some asynchronous code in the function, but only if you await something within the function.
In Swift concurrency, the Result type is no longer needed and quickly becomes syntactic noise. In an async function, you simply either return a value, or throw an error.
Let us assume that isEvenNumber is just a placeholder for something sufficiently complicated that you did need to make it asynchronous to avoid blocking the current actor. Furthermore, while you do not throw errors, let us assume that this is a proxy for some method that would.
If all of that were the case, you would need to make sure that you get it off the current actor with a detached task, and then it would be asynchronous, as you would await its value. And I am arbitrarily defining isEven to throw an error if the value is negative. (Clearly, this is not a reasonable reason to throw an error, but included it for illustrative purposes.)
Thus:
enum NumberError: Error {
case negative
}
// This is not sufficiently computationally intensive to warrant making it run
// asynchronously, but let us assume that it was. You would do something like:
func isEven(_ num: Int) async throws -> Bool {
if num < 0 { throw NumberError.negative }
return await Task.detached {
num.isMultiple(of: 2)
}.value
}
func profileAsyncFunc() async throws -> Bool {
try await isEven(3)
}
Then you could do:
Task {
let isEven = try await profileAsyncFunc()
print(isEven)
}
You said:
I'm trying to receive an async function return value inside a flatMap …
Why? You do not need flatMap in Swift concurrency, as you might use in Combine.
If you are simply trying to adopt async-await, you can just excise this from your code. If there is some other problem that you are trying to solve by introducing flatMap, please edit the question providing a more complete example, and explain the intended rationale for flatMap.
As it stands, the example is sufficiently oversimplified that it makes it hard for us to understand the problem you are really trying to solve.

Elegant way to execute code on function exit in Dart

Suppose we need to execute some code when a function finishes, no matter how.
Example:
void myFunc() async {
await myLock.acquire();
if(...) {
myLock.release();
return;
}
...
myLock.release();
}
Many languages have features that allow to achieve this in a more elegant way than just manually calling myLock.release() before every return statement (For example defer in Go). Is something like that also possible in Dart?
Dart does not have RAII. You instead would need to use try-finally.
(Dart did recently (in 2.17) add Finalizers, but those would fire when objects are garbage collected, which might happen at some non-deterministic time, if ever.)
And just for the record, an example of using try/finally:
void myFunc() async {
await myLock.acquire();
try {
if(...) {
return;
}
...
} finally {
myLock.release();
}
}
You'd want to start the try after allocating the resource, so that you don't try to release if allocation throws.

forEach vs for in: Different Behavior When Calling a Method

I noticed that forEach and for in to produce different behavior. I have a list of RegExp and want to run hasMatch on each one. When iterating through the list using forEach, hasMatch never returns true. However, if I use for in, hasMatch returns true.
Sample code:
class Foo {
final str = "Hello";
final regexes = [new RegExp(r"(\w+)")];
String a() {
regexes.forEach((RegExp reg) {
if (reg.hasMatch(str)) {
return 'match';
}
});
return 'no match';
}
String b() {
for (RegExp reg in regexes) {
if (reg.hasMatch(str)) {
return 'match';
}
}
return 'no match';
}
}
void main() {
Foo foo = new Foo();
print(foo.a()); // prints "no match"
print(foo.b()); // prints "match"
}
(DartPad with the above sample code)
The only difference between the methods a and b is that a uses forEach and b uses for in, yet they produce different results. Why is this?
Although there is a prefer_foreach lint, that recommendation is specifically for cases where you can use it with a tear-off (a reference to an existing function). Effective Dart recommends against using Iterable.forEach with anything else, and there is a corresponding avoid_function_literals_in_foreach_calls lint to enforce it.
Except for those simple cases where the callback is a tear-off, Iterable.forEach is not any simpler than using a basic and more general for loop. There are more pitfalls using Iterable.forEach, and this is one of them.
Iterable.forEach is a function that takes a callback as an argument. Iterable.forEach is not a control structure, and the callback is an ordinary function. You therefore cannot use break to stop iterating early or use continue to skip to the next iteration.
A return statement in the callback returns from the callback, and the return value is ignored. The caller of Iterable.forEach will never receive the returned value and will never have an opportunity to propagate it. For example, in:
bool f(List<int> list) {
for (var i in list) {
if (i == 42) {
return true;
}
}
return false;
}
the return true statement returns from the function f and stops iteration. In contrast, with forEach:
bool g(List<int> list) {
list.forEach((i) {
if (i == 42) {
return true;
}
});
return false;
}
the return true statement returns from only the callback. The function g will not return until it completes all iterations and reaches the return false statement at the end. This perhaps is clearer as:
bool callback(int i) {
if (i == 42) {
return true;
}
}
bool g(List<int> list) {
list.forEach(callback);
return false;
}
which makes it more obvious that:
There is no way for callback to cause g to return true.
callback does not return a value along all paths.
(That's the problem you encountered.)
Iterable.forEach must not be used with asynchronous callbacks. Because any value returned by the callback is ignored, asynchronous callbacks can never be waited upon.
I should also point out that if you enable Dart's new null-safety features, which enable stricter type-checking, your forEach code will generate an error because it returns a value in a callback that is expected to have a void return value.
A notable case where Iterable.forEach can be simpler than a regular for loop is if the object you're iterating over might be null:
List<int>? nullableList;
nullableList?.forEach((e) => ...);
whereas a regular for loop would require an additional if check or doing:
List<int>? nullableList;
for (var e in nullableList ?? []) {
...
}
(In JavaScript, for-in has unintuitive pitfalls, so Array.forEach often is recommended instead. Perhaps that's why a lot of people seem to be conditioned to use a .forEach method over a built-in language construct. However, Dart does not share those pitfalls with JavaScript.)
👋 jamesdin! Everything you have shared about the limitations of forEach is correct however there's one part where you are wrong. In the code snippet showing the example of how you the return value from forEach is ignored, you have return true; inside the callback function for forEach which is not allowed as the callback has a return type of void and returning any other value from the callback is not allowed.
Although you have mentioned that returning a value from within the callback will result in an error, I'm just pointing at the code snippet.
Here's the signature for forEach
Also, some more pitfalls of forEach are:
One can't use break or continue statements.
One can't get access to the index of the item as opposed to using the regular for loop

Is this loginRequired(f)() the way to handle login required functions in dart?

I am new to Dart programming. I am trying to figure out what is the proper way (what everyone will do) to handle/guard those functions which are login required. The following is my first trial:
$ vim login_sample.dart:
var isLoggedIn;
class LoginRequiredException implements Exception {
String cause;
LoginRequiredException(this.cause);
}
Function loginRequired(Function f) {
if (!isLoggedIn) {
throw new LoginRequiredException("Login is reuiqred.");
}
return f;
}
void secretPrint() {
print("This is a secret");
}
void main(List<String> args) {
if (args.length != 1) return null;
isLoggedIn = (args[0] == '1') ? true : false;
try {
loginRequired(secretPrint)();
} on LoginRequiredException {
print("Login is required!");
}
}
then, run it with $ dart login_sample.dart 1 and $ dart login_sample.dart 2.
I am wondering if this is the recommended way to guard login required functions or not.
Thank you very much for your help.
Edited:
My question is more about general programming skills in Dart than how to use a plugin. In python, I just need to add #login_required decorator in the front of the function to protect it. I am wondering if this decorator function way is recommended in dart or not.
PS: All firebase/google/twitter/facebook etc... are blocked in my country.
I like the functional approach. I'd only avoid using globals, you can wrap it in a Context so you can mock then for tests and use Futures as Monads: https://dartpad.dartlang.org/ac24a5659b893e8614f3c29a8006a6cc
Passing the function is not buying much value. In a typical larger Dart project using a framework there will be some way to guard at a higher level than a function - such as an entire page or component/widget.
If you do want to guard at a per-function level you first need to decide with it should be the function or the call site that decides what needs to be guarded. In your example it is the call site making the decision. After that decision you can implement a throwIfNotAuthenticated and add a call at either the definition or call site.
void throwIfNotAuthenticated() {
if (!userIsAuthenticated) {
throw new LoginRequiredException();
}
}
// Function decides authentication is required:
void secretPrint() {
throwIfNotAuthenticated();
print('This is a secret');
}
// Call site decides authentication is required:
void main() {
// do stuff...
throwIfNotAuthenticated();
anotherSecreteMethod();
}

Resources