How do I pass Eio 'env'?

Hello,

The following code works if I create a file first. The directory permissions are proper. And I also noticed there are two Eio_main.run . I believe there should only be one. So I tried to pass env by declaring it in the sig but the type looks odd. So I am wondering now about how to pass env around.

Am I using the pattern wrongly ?

module type WalWriter =
sig
  val write : bytes  ->  unit
  val read :   unit->string
end
module WalWriter = struct

let write (data : bytes)  =
  let ( / ) = Eio.Path.( / ) in
    Eio_main.run @@ fun env ->
      let path = Eio.Stdenv.fs env  in
      let p = path / "/Users"/"anu"/"Documents"/"rays"/"Bitcask"/"bitcask"/"bitcask.log" in
      Eio.Path.with_open_out ~append:true ~create:(`If_missing 0o600) p (fun f ->
      try
          let bytes_written =
           Eio.Flow.single_write f  [Cstruct.of_bytes
                                                 data]
          in Printf.printf "%d bytes written" bytes_written
     with
       |  ex -> traceln "%a" Eio.Exn.pp ex
     )

let read ()=
let ( / ) = Eio.Path.( / ) in
 Eio_main.run @@ fun env ->
  let path = Eio.Stdenv.fs env in
  let p = path / "/Users"/"anu"/"Documents"/"rays"/"Bitcask"/"bitcask"/"bitcask.log" in
  let lines =
  if  (Sys.file_exists  "/Users/anu/Documents/rays/Bitcask/bitcask/bitcask.log") then
   Eio.Path.load p
  else
     raise Not_found
  in lines

end

Update :

module type WalWriter =
sig
  val write : bytes -> Eio_unix.Stdenv.base ->  unit
  val read :   unit -> Eio_unix.Stdenv.base -> string
end

This compiles and I have removed the redundant Eio_main.run

Thanks.

Hi @Mohan_Radhakrishnan,

Looks like you got it sorted for your particular example.

I will add that one of the main ideas behind Eio is to pass in only those things that your function needs. The standard environment contains a host of things (like process spawning, network access etc.) that perhaps your functions do not need. It seems your WalWriter modules may only need access to the filesystem capability, in which case you could change the API to be:

module type WalWriter =
sig
  val write : bytes -> _ Eio.Path.t ->  unit
  val read :   unit -> _ Eio.Path.t -> string
end

Now, from an Eio point of view, these functions are hopefully not doing anything with the other capabilities!

You can read more about this in the documentation and also on @talex5’s blog post. Note that if “pulling out” the capabilities is too cumbersome and/or passing in multiple arguments is not desirable you can always use subtyping too :))

I think a more typical signature would be:

module type WalWriter = sig
  val path  : _ Eio.Path.t
  val write : bytes -> unit
  val read  : unit -> string
end

Then for the implementation you’d have to do:

let ( / ) = Eio.Path.( / )

let main env =
  ...
  let module Impl = struct
    let path = Eio.Stdenv.fs env / ...

    let write data = Eio.Path.with_open_out ... path ...

    let read () =
      ... Eio.Path.load path ...
  end
  in
  ...

Alternatively, you could make a functor to pass the path in to the module:

module MakeWalWriter(P : sig val path : _ Eio.Path.t end) = struct
  let write data = Eio.Path.with_open_out ... P.path ...

  let read () =
    ... Eio.Path.load P.path ...
end
1 Like