Skip to content

Consider Ref_alloc and Ref_uninit primitives #209

@MatthewFluet

Description

@MatthewFluet

It would be possible to extend the ideas from #207 to references. For example, we could have:

structure Unsafe.Ref:
  sig
    val alloc: unit -> 'a ref
    val uninit: 'a ref -> unit
    structure Raw:
      sig
        type 'a rawref
        val alloc: unit -> 'a rawref
        val toRef: 'a rawref -> 'a ref
        val uninit: 'a rawref -> unit
      end
  end

One potential motivation is to eliminate the (admittedly small) dispatch overhead in a ('a -> 'b) ref that is only ever meant to hold one function. For example, recall the classic "back-patching" technique for recursion with first-class functions and references:

val fact_ref = ref (fn _ => raise Fail "fact")
val fact = fn n => if n <= 1 then 1 else n * (!fact_ref) (n - 1)
val () = fact_ref := fact

Control-flow analysis will determine that the contents of fact_ref is either fn _ => raise Fail "fact" or fn n => ..., and the application (!fact_ref) (n - 1) will have a case-analysis to select between these functions. [Note that the overhead is essentially the same, but more obvious to the programmer, when using an ('a -> 'b) option ref.]

With a Ref_alloc primitive, one could write:

val fact_ref = Unsafe.Ref.alloc ()
val fact = fn n => if n <= 1 then 1 else n * (!fact_ref) (n - 1)
val () = fact_ref := fact

Control-flow analysis will determine that the contents of fact_ref is only fn n => ... and the application will have a single (exhaustive) case-match. Subsequent ConstantPropagation and/or Useless optimizations would probably eliminate the reference entirely.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions