Quantcast
Channel: ReScript Forum - Latest posts
Viewing all articles
Browse latest Browse all 2592

Module functors vs. records-of-functions for interface/implementation separation

$
0
0

if you really need to pass around some dependencies, I’d likely use something like that:

module DepsTypes = {
  module type Console = {
    let log: string => unit
  }

  module type T = {
    module Console: Console
  }
}

module Deps: DepsTypes.T = {
  module Console: DepsTypes.Console = Console
}

module File1 = {
  let bar = (a, b, ~deps=module(Deps: DepsTypes.T)) => {
    let module(Deps) = deps
    Deps.Console.log(Int.toString(a + b))
  }
}

File1.bar(1, 2)

module TestFile1 = {
  module Console = {
    let logs = ref("")
    let log = s => {logs := logs.contents + s}
    let flushLog = () => {logs := ""}
  }
  let deps = module(
    {
      module Console = Console
    }: DepsTypes.T
  )

  let testBar = {
    Console.flushLog()
    File1.bar(1, 2, ~deps)
    assertEqual(Console.logs.contents, "3")
  }
}

But even in such cases, I’d likely rather pass only the dependencies needed instead of a dependency root:

module DepsTypes = {
  module type Console = {
    let log: string => unit
  }

  module type T = {
    module Console: Console
  }
}

module Deps: DepsTypes.T = {
  module Console: DepsTypes.Console = Console
}

module File1 = {
  let bar = (a, b, ~console=module(Deps.Console: DepsTypes.Console)) => {
    let module(Console) = console
    Console.log(Int.toString(a + b))
  }
}

File1.bar(1, 2)

module TestFile1 = {
  module Console = {
    let logs = ref("")
    let log = s => {logs := logs.contents + s}
    let flushLog = () => {logs := ""}
  }
  let console = module(Console: DepsTypes.Console)

  let testBar = {
    Console.flushLog()
    File1.bar(1, 2, ~console)
    assertEqual(Console.logs.contents, "3")
  }
}

Viewing all articles
Browse latest Browse all 2592

Trending Articles