@@ -1524,19 +1524,26 @@ See Eio's own tests for examples, e.g., [tests/switch.md](tests/switch.md).
15241524## Provider Interfaces
15251525
15261526Eio applications use resources by calling functions (such as ` Eio.Flow.write ` ).
1527- These functions are actually wrappers that call methods on the resources.
1527+ These functions are actually wrappers that look up the implementing module and call
1528+ the appropriate function on that.
15281529This allows you to define your own resources.
15291530
15301531Here's a flow that produces an endless stream of zeros (like "/dev/zero"):
15311532
15321533``` ocaml
1533- let zero = object
1534- inherit Eio.Flow.source
1534+ module Zero = struct
1535+ type t = unit
15351536
1536- method read_into buf =
1537+ let single_read () buf =
15371538 Cstruct.memset buf 0;
15381539 Cstruct.length buf
1540+
1541+ let read_methods = [] (* Optional optimisations *)
15391542end
1543+
1544+ let ops = Eio.Flow.Pi.source (module Zero)
1545+
1546+ let zero = Eio.Resource.T ((), ops)
15401547```
15411548
15421549It can then be used like any other Eio flow:
@@ -1549,34 +1556,6 @@ It can then be used like any other Eio flow:
15491556- : unit = ()
15501557```
15511558
1552- The ` Flow.source ` interface has some extra methods that can be used for optimisations
1553- (for example, instead of filling a buffer with zeros it could be more efficient to share
1554- a pre-allocated block of zeros).
1555- Using ` inherit ` provides default implementations of these methods that say no optimisations are available.
1556- It also protects you somewhat from API changes in future, as defaults can be provided for any new methods that get added.
1557-
1558- Although it is possible to * use* an object by calling its methods directly,
1559- it is recommended that you use the functions instead.
1560- The functions provide type information to the compiler, leading to clearer error messages,
1561- and may provide extra features or sanity checks.
1562-
1563- For example ` Eio.Flow.single_read ` is defined as:
1564-
1565- ``` ocaml
1566- let single_read (t : #Eio.Flow.source) buf =
1567- let got = t#read_into buf in
1568- assert (got > 0 && got <= Cstruct.length buf);
1569- got
1570- ```
1571-
1572- As an exception to this rule, it is fine to use the methods of ` env ` directly
1573- (e.g. using ` main env#stdin ` instead of ` main (Eio.Stdenv.stdin env) ` .
1574- Here, the compiler already has the type from the ` Eio_main.run ` call immediately above it,
1575- and ` env ` is acting as a simple record.
1576- We avoid doing that in this guide only to avoid alarming OCaml users unfamiliar with object syntax.
1577-
1578- See [ Dynamic Dispatch] ( doc/rationale.md#dynamic-dispatch ) for more discussion about the use of objects here.
1579-
15801559## Example Applications
15811560
15821561- [ gemini-eio] [ ] is a simple Gemini browser. It shows how to integrate Eio with ` ocaml-tls ` and ` notty ` .
@@ -1729,9 +1708,8 @@ Of course, you could use `with_open_in` in this case to simplify it further.
17291708
17301709### Casting
17311710
1732- Unlike many languages, OCaml does not automatically cast objects (polymorphic records) to super-types as needed.
1711+ Unlike many languages, OCaml does not automatically cast to super-types as needed.
17331712Remember to keep the type polymorphic in your interface so users don't need to do this manually.
1734- This is similar to the case with polymorphic variants (where APIs should use ` [< ...] ` or ` [> ...] ` ).
17351713
17361714For example, if you need an ` Eio.Flow.source ` then users should be able to use a ` Flow.two_way `
17371715without having to cast it first:
@@ -1741,13 +1719,13 @@ without having to cast it first:
17411719(* BAD - user must cast to use function: *)
17421720module Message : sig
17431721 type t
1744- val read : Eio.Flow.source -> t
1722+ val read : Eio.Flow.source_ty r -> t
17451723end
17461724
17471725(* GOOD - a Flow.two_way can be used without casting: *)
17481726module Message : sig
17491727 type t
1750- val read : # Eio.Flow.source -> t
1728+ val read : _ Eio.Flow.source -> t
17511729end
17521730```
17531731
@@ -1756,20 +1734,18 @@ If you want to store the argument, this may require you to cast internally:
17561734``` ocaml
17571735module Foo : sig
17581736 type t
1759- val of_source : # Eio.Flow.source -> t
1737+ val of_source : _ Eio.Flow.source -> t
17601738end = struct
17611739 type t = {
1762- src : Eio.Flow.source ;
1740+ src : Eio.Flow.source_ty r ;
17631741 }
17641742
17651743 let of_source x = {
1766- src = (x :> Eio.Flow.source );
1744+ src = (x :> Eio.Flow.source_ty r );
17671745 }
17681746end
17691747```
17701748
1771- Note: the ` #type ` syntax only works on types defined by classes, whereas the slightly more verbose ` <type; ..> ` works on all object types.
1772-
17731749### Passing env
17741750
17751751The ` env ` value you get from ` Eio_main.run ` is a powerful capability,
0 commit comments