maybe i’m not being clear. there are two main concepts i’m discussing here: interfaces (think ports and adapters) and a composition root (think dependency injection)
i understand your point on injecting functions as needed, but that doesnt really make sense for larger applications where functions are often bundled together to model a behavior (i.e., log info/debug/warn/error or even more so, a repository with getbyid, getall, save, modify etc).
the way i usually do it is a sort of “hexagonal domain-driven architecture” and if we stick to the ports/adapters part of that, i do ports (e.g. Clock.t = {now:unit=>float}) and adapters (e.g. SystemClock which has now=()=>Date.now)
so the question here is, what is preferrable to model interfaces (think interface IClock in typescript):
A:
// Clock.res
type t = {
now: unit => float
}
// SystemClock.res (i understand `make` isnt right for SystemClock in particular as its a singleton instance, but ignore that for now)
let make = (): Clock.t = {
{now: () => Date.now()}
}
or B:
// Clock.res
module type T = {
let now: unit => float
}
// SystemClock.res
let now = () => Date.now()
so this is the first question, whats the better way to model interfaces in rescript.
the second question tied into the first is what’s better considering we’re doing dependency injection starting at the composition root, e.g. Deps.res, where we wire everything up:
A:
// Deps.res
type t = {
clock: Clock.t
}
let make = () => {
let clock = SystemClock.make()
{ clock: clock }
}
or B:
// Deps.res
type t = {
clock: module(Clock.T)
}
let make = () => {
module ClockImpl = SystemClock
{ clock: module(ClockImpl) }
}
so this question is, with dependency injection in mind, do we prefer A or B?
you might also suggest another alternative, i.e. injecting functions directly, but to me, that only makes sense for trivial cases. instead, imagine a larger port/interface with maybe 5 different functions that together model a behavior (again, think repository, get, set, search, getall, modifu, overwrite, whatever, these functions will be coupled together as they all work with the same persistence layer, so should not be passed around individually?)
third, my question is what’s the difference between these two and what are their uses and when do i prefer whta:
A:
module Log = unpack(deps.getLog("foo"))
or B:
let module(Log) = deps.getLog("foo")
trying to really wrap my head around the right way to think in rescript terms here