romanchechyotkin / nats.ocaml

OCaml client for NATS, the cloud native messaging system.
Apache License 2.0
10 stars 2 forks source link

Improve library API #1

Closed dx3mod closed 2 months ago

dx3mod commented 2 months ago

Some suggestions for improving library's API.

Labeled functions

(* now *)
Client.connect host port
(* with labeled arguments *)
Client.connect ~host ~port ()

You can also set defaults for them

(* now *)
let connect host port = ...
(* with defaults *)
let connect ?(host = default_host) ?(port = default_port) () = ...

or use modules

let conn = Client.connect (module struct 
  let host = ..
  let port = ...
 end)

with_connect

Automatically close a resource

(* now *) 
let conn = Client.connect ()
...
Client.close conn

(* with with_connect *)
Client.with_connect ... @@ fun conn -> 
  ...

first-class modules or objects for connection

(* object *)
Client.with_connect ~host ~port (fun conn -> 
  conn#pub "FOO")

(* first-class module *)
Client.with_connect ~host ~port (fun (module Conn) -> 
  Conn.pub "FOO")

signature for abstraction

(* now *)
type 'a t = { sockaddr : sockaddr; socket : Lwt_unix.file_descr }
(* should be *)
type 'a t

Module signatures hide internal implementation.

unsafe

In some cases you can use unsafe functions (read this)

(* now *)
let msg : bytes = Bytes.of_string message 
(* better performance *)  
let msg  = Bytes.unsafe_of_string message 

print_endline

:cactus:

monadic syntax

Prefer monadic syntax let*, let+, or ppx_lwt.

romanchechyotkin commented 2 months ago

Tnaks a lot, but question ,can i use labeled args with optional together? image Ocaml does not allow me to do that @dx3mod

romanchechyotkin commented 2 months ago

So i found the answer, unit type at the end is the necessary thing image and now i have these things image

dx3mod commented 2 months ago

Yes, otherwise OCaml won't know where to stop.

dx3mod commented 2 months ago

@romanchechyotkin, you may make a payload argument for sub/pub functions positional, which makes partial application more comfortable.

let notify  = Client.pub ~client ~subject:"NOTIFY" 
(* val notify : payload -> unit Lwt.t *)

value 
|> do_something_a
|> do_something_b
|> notify