Skip to content
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

Generalize Client #72

Closed
wants to merge 2 commits into from
Closed

Conversation

edsko
Copy link
Collaborator

@edsko edsko commented Apr 19, 2023

The type of run is

run :: ClientConfig -> Config -> Client a -> IO a

which looks reasonable enough. However, Client is a synonym for

type Client a = (Request -> (Response -> IO a) -> IO a) -> IO a

The client is given a sendRequest function which it can use to send requests, as long as it provides a way to process the response. That too is reasonable, but the confusing part is the use of a in the type of sendRequest: why does this have to be related to the final result of the Client? It seems to suggest that perhaps all of these are collected in some way, but of course that cannot be the case since (the result would have to be IO [a] or something).

Indeed, if we look at the code, there is no relation; in this commit we therefore generalize Client to

type Client a = (forall b. Request -> (Response -> IO b) -> IO b) -> IO a

This makes more sense: we get a callback that we can call as often as we we like; whatever type we get back when we process the response is the result of that callback; and we then use this callback to produce the final result, whatever it is.

This requires no code changes in the library at all; just needs RankNTypes enabled in a few modules.

Backwards compatibility: this is strictly a generalization of the existing API, so existing code will continue to work; it just gets a more precise type, and can do more. However, there is one limitation, which is why I had to modify one of the tests in the test suite: where before we could have a [Client ()], that is no longer possible (as it would require impredicativity). I suspect that this will not really be an issue, but I do not know for sure.

The type of `run` is

```haskell
run :: ClientConfig -> Config -> Client a -> IO a
```

which looks reasonable enough. However, `Client` is a synonym for

```haskell
type Client a = (Request -> (Response -> IO a) -> IO a) -> IO a
```

The client is given a `sendRequest` function which it can use to send requests,
as long as it provides a way to process the response. That too is reasonable,
but the confusing part is the use of `a` in the type of `sendRequest`: why does
this have to be related to the final result of the `Client`? It seems to
suggest that perhaps all of these are collected in some way, but of course that
cannot be the case since (the result would have to be `IO [a]` or something).

Indeed, if we look at the code, there _is_ no relation; in this commit we
therefore generalize `Client` to

```haskell
type Client a = (forall b. Request -> (Response -> IO b) -> IO b) -> IO a
```

This makes more sense: we get a callback that we can call as often as we we
like; whatever type we get back when we process the response is the result of
that callback; and we then use this callback to produce the final result,
whatever it is.

This requires _no_ code changes in the library at all; just needs `RankNTypes`
enabled in a few modules.

**Backwards compatibility**: this is strictly a generalization of the existing
API, so existing code will continue to work; it just gets a more precise type,
and can do more. _However_, there is one limitation, which is why I had to
modify one of the tests in the test suite: where before we could have a
`[Client ()]`, that is no longer possible (as it would require
impredicativity). I suspect that this will not really be an issue, but I do not
know for sure.
@kazu-yamamoto kazu-yamamoto self-requested a review April 20, 2023 07:07
clients = [client0,client1,client2,client3,client3',client3'',client4,client5]

client :: C.Client ()
client sendRequest = mapConcurrently_ id $ [
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can use foldr1 concurrently_ instead of mapConcurrently_ id $ .

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, that would be equivalent.

@edsko
Copy link
Collaborator Author

edsko commented Apr 20, 2023

Pushed a commit that uses foldr1 concurrently_ instead of mapConcurrently_ id. To avoid ambiguity errors, removed the unqualified import of Data.ByteString.Char8 and qualified one use of isPrefixOf as C8.isPrefixOf (that C8 qualifier was already there).

@kazu-yamamoto kazu-yamamoto self-requested a review April 20, 2023 11:06
Copy link
Owner

@kazu-yamamoto kazu-yamamoto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

kazu-yamamoto added a commit that referenced this pull request Apr 20, 2023
@kazu-yamamoto
Copy link
Owner

Rebased and merged. Thank you for your contribution!

@edsko edsko deleted the edsko/generalize-Client branch April 20, 2023 11:22
@edsko edsko mentioned this pull request Apr 20, 2023
edsko added a commit to edsko/http2 that referenced this pull request Apr 20, 2023
This was a remnant of kazu-yamamoto#72 (CI did not run, I guess).
@edsko
Copy link
Collaborator Author

edsko commented Jul 14, 2023

@kazu-yamamoto , how does your release process work? I noticed that 4.1.4 includes #78 so I figured I'd give it a go instead of my local branch (I was going to try http2-tls), but when I got compilation failures, and I realized that this commit is not included in the release. Is that intentional?

@kazu-yamamoto
Copy link
Owner

  • v4.1 was created to keep the backward compatibility for Client but to switch to crypton. Non-breaking changes are included.
  • master will be v4.2 for this PR. I'm waiting for your another PR.

@edsko
Copy link
Collaborator Author

edsko commented Jul 15, 2023

Ok, perfect, makes total sense! Re other PR, I'm inching closer towards that; lot of stuff needed to happen on my side before I could focus on http2 again but nearly there.

akshaymankar pushed a commit to wireapp/http2 that referenced this pull request Nov 8, 2023
This was a remnant of kazu-yamamoto#72 (CI did not run, I guess).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants