ocaml-multicore / eio

Effects-based direct-style IO for multicore OCaml
Other
528 stars 67 forks source link

Support: sockets as flows with compatible poly variants #736

Open cdaringe opened 1 month ago

cdaringe commented 1 month ago

Hey friends! Candidly, this is a support request for eio migration/upgrade. If you want me to go to S.O., that's fine.

Problem

I upgraded eio, and suffered some breaking changes, for which I cannot recover. I use ocaml so infrequently these days that I could use a bump handling the update gracefully

Context

I have two modules of interest:

During migration, polymorphic variants are now all over socket and flow types.

Let's check it out:

217 |   let dispatchers_by_road_id = Hashtbl.create 10
            ^^^^^^^^^^^^^^^^^^^^^^
  The type of this value,
  (int, ([> `Generic ] as '_weak1) Eio.Net.stream_socket_ty Eio__.Flow.sink)
  Hashtbl.t, contains the non-generalizable type variable(s) '_weak1.

Dang, it used to be inferable. Ok, so what can I put in there now instead?

Well, the code that produces the socket handler (let socket = Eio.Net.datagram_socket ~sw net addr ) gives a 'tag datagram_socket_ty t, which is inferred to [> `Generic ] datagram_socket_ty t. Something tells me this may be too narrow of a type already? Unsure.

Let's try using that inferred by anyway to dodge the compilation error:

  let dispatchers_by_road_id: (int, [`Generic] Eio.Net.datagram_socket_ty Resource.t) Hashtbl.t = Hashtbl.create 10

Shoot, now downstream I get:

Type
  [ `Generic ] Net.datagram_socket_ty =
    [ `Close | `Datagram | `Platform of [ `Generic ] | `Shutdown | `Socket ]
is not compatible with type [> Eio__Flow.sink_ty ] = [> `Flow | `W ]

Which sure kinda makes sense... i'm just not clear from reading the docs and examples how to best express my types and interoperate between socket and flow primitives?

If you wanna see the actual code, this failure is present here: https://github.com/cdaringe/protohacks/tree/im-bad-at-ocaml-im-sorry and produces the errors discussed above.

No pressure to help :shrug:, can't hurt to ask :)

talex5 commented 3 weeks ago

The "non-generalizable type variable" happens in cases like this:

$ cat a.ml
let x = ref None

$ ocamlopt -c a.ml
File "a.ml", line 1, characters 4-5:
1 | let x = ref None
        ^
Error: The type of this expression, '_weak1 option ref,
       contains the non-generalizable type variable(s): '_weak1.
       (see manual section 6.1.2)

Giving it a concrete type is the solution, as you found.

The other problem looks like you're trying to use a datagram (message based) socket as a flow (byte-stream), which doesn't really make sense. For example, if you try to write "hello" to a flow and the kernel says it wrote 3 bytes then we do another call to send remaining the "lo" bit, but you don't want to do that with a datagram socket.