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

Add an example for Refs #32

Open
leostera opened this issue Jan 2, 2024 · 6 comments
Open

Add an example for Refs #32

leostera opened this issue Jan 2, 2024 · 6 comments

Comments

@leostera
Copy link
Collaborator

leostera commented Jan 2, 2024

At the moment refs are used in a few places like Mint Tea but there's no good explanation of what they are.

We should add a little example and document them, and maybe consider renaming them to something like Rune or some word that isn't taken in OCaml (like "ref") is, so we can introduce it as new concept.

@wonbyte
Copy link
Contributor

wonbyte commented Jan 5, 2024

Could you point me to an example in Mint Tea? I looked up Ocaml refs and they seem to just be Pointers but when I see Rune I think of Golang rune and Code Point.

@leostera
Copy link
Collaborator Author

leostera commented Jan 5, 2024

Here's an example from minttea: https://github.com/leostera/minttea/blob/4f9938c212230898360d009d60689787e51a632f/examples/stopwatch/main.ml#L15-L16

The gist is that a Ref is unique reference across the entire execution of your program. No two calls to Ref.make () will ever return the same 'a Ref.t.

If you look at how they're implemented, a 'a Ref.t is really just an int64 (so a potentially really large int) with an associated type parameter.

What's good about them is that if you send them somewhere, and you get it back, then you can be 100% certain that this was the exact same value that you created first.

Which has some cool implications for static typing of values, because if we can guarantee that two refs are the same, then we know that the type parameter they both have must be the same.

We use this so that if we send and receive a message and the refs are the same, we can cast a message type to the expected type. A little dynamic type-checking for when the OCaml type system doesn't help.

Hope this helps!

Renaming to Rune was just a random idea, maybe its enough to document Refs better :)

@wonbyte
Copy link
Contributor

wonbyte commented Jan 5, 2024

What about naming it some along the lines of Marker, which "marks" a unique piece of memory? As someone new to Ocaml seeing:

(** `Ref` here *)
let ref = Riot.Ref.make ()

(** `ref` here *)
let init _ = Command.Seq [ Set_timer (ref, 1.0); Enter_alt_screen ]

it may be somewhat confusing to call it Ref especially since "casing" matters in Ocaml.

So something like

(** a [Marker] is unique reference across the entire execution of your program. 
      No two calls to [Marker.make ()] will ever return the same ['a Marker.t]. *)

type 'a t = Marker : int64 -> 'a t [@@unboxed]

let __current__ = Atomic.make 0L
let pp ppf (Marker pid) = Format.fprintf ppf "#Marker<%s>" (Int64.to_string pid)

let rec make () =
  let last = Atomic.get __current__ in
  let current = last |> Int64.succ in
  if Atomic.compare_and_set __current__ last current then Marker last else make ()

let equal (Marker a) (Marker b) = Int64.equal a b

let type_equal : type a b. a t -> b t -> (a, b) Type.eq option =
 fun a b ->
  match (a, b) with
  | Marker a', Marker b' when Int64.equal a' b' -> Some (Obj.magic Type.Equal)
  | _ -> None

let is_newer (Marker a) (Marker b) = Int64.compare a b = 1
let hash (Marker a) = Int64.hash a

module Map = Util.Dashmap.Make (struct
  type key = unit t

  let hash = hash
  let equal = equal
end)

@dmmulroy
Copy link

dmmulroy commented Jan 6, 2024

This is a similar concept as Symbols1 in the JavaScript world. Names I like for this feature in order of preference:

Symbol
Brand
Rune

Footnotes

@wonbyte
Copy link
Contributor

wonbyte commented Jan 6, 2024

Thanks @dmmulroy. Symbol is perfect!

@alexeyshch
Copy link

For me, as an Erlang user, Ref is perfect, as it has the same purpose as Erlang's references.

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

No branches or pull requests

4 participants