{"id":14066795,"url":"https://github.com/wahani/modules","last_synced_at":"2026-03-06T18:03:06.076Z","repository":{"id":2053381,"uuid":"45627580","full_name":"wahani/modules","owner":"wahani","description":"Modules in R","archived":false,"fork":false,"pushed_at":"2024-01-20T15:44:15.000Z","size":333,"stargazers_count":84,"open_issues_count":5,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-12-09T12:15:50.185Z","etag":null,"topics":["cran","functional-programming","module","r"],"latest_commit_sha":null,"homepage":"https://cran.r-project.org/package=modules","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wahani.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2015-11-05T17:27:03.000Z","updated_at":"2025-12-06T06:44:38.000Z","dependencies_parsed_at":"2024-01-27T14:55:52.318Z","dependency_job_id":null,"html_url":"https://github.com/wahani/modules","commit_stats":{"total_commits":149,"total_committers":2,"mean_commits":74.5,"dds":"0.10067114093959728","last_synced_commit":"7578c5b6ef779bfd3e4d5e4da1a47189480ffc63"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/wahani/modules","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wahani%2Fmodules","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wahani%2Fmodules/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wahani%2Fmodules/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wahani%2Fmodules/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wahani","download_url":"https://codeload.github.com/wahani/modules/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wahani%2Fmodules/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30189483,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T17:33:53.563Z","status":"ssl_error","status_checked_at":"2026-03-06T17:33:51.678Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cran","functional-programming","module","r"],"created_at":"2024-08-13T07:05:15.928Z","updated_at":"2026-03-06T18:03:06.042Z","avatar_url":"https://github.com/wahani.png","language":"R","funding_links":[],"categories":["R"],"sub_categories":[],"readme":"[![Build Status](https://github.com/wahani/modules/actions/workflows/rcmdcheck.yml/badge.svg?branch=main)](https://github.com/wahani/modules/actions)\n[![codecov.io](https://codecov.io/github/wahani/modules/coverage.svg?branch=master)](https://codecov.io/github/wahani/modules?branch=master)\n[![CRAN](http://www.r-pkg.org/badges/version/modules)](https://cran.r-project.org/package=modules)\n![Downloads](http://cranlogs.r-pkg.org/badges/modules)\n# Modules in R\n\nProvides modules as an organizational unit for source code. Modules enforce to be more rigorous when defining dependencies and have a local search path. They can be used as a sub unit within packages or in scripts.\n\n## Installation\n\nFrom CRAN:\n\n```r\ninstall.packages(\"modules\")\n```\n\nFrom GitHub:\n\n\n```r\nif (require(\"devtools\")) install_github(\"wahani/modules\")\n```\n\n# Introduction\n\nThe key idea of this package is to provide a unit of source code which has it's\nown scope. The main and most reliable infrastructure for such organizational\nunits in the R ecosystem is a package. Modules can be used as stand alone,\nad-hoc substitutes for a package or as a sub-unit within a package.\n\nWhen modules are defined inside of packages they act as bags of functions (like\nobjects as in object-oriented-programming). Outside of packages modules define\nentities which only know of the base environment, i.e. within a module the base\nenvironment is the only *package* on the *search path*. Also they are always\nrepresented as a list inside R.\n\n## Scoping of modules\n\nWe can create a module using the `modules::module` function. A module is similar\nto a function definition; it comprises:\n\n- the body of the module\n- the environment in which it is created (defined implicitly)\n- the environment used for the search path, in most cases `baseenv()` (defined\nimplicitly)\n\nSimilar to a function you may supply arguments to a module; see the vignette on\nmodules as objects on this topic.\n\nTo illustrate the very basic functionality of a module, consider the following\nexample:\n\n\n```r\nlibrary(\"modules\")\nm \u003c- module({\n  foo \u003c- function() \"foo\"\n})\nm$foo()\n```\n\n```\n## [1] \"foo\"\n```\n\nHere `m` is the collection of objects created inside the module. This is a\n`list` with the function `foo` as only element. We can do the same thing and define a module in a separate file:\n\n**module.R**\n\n```\nfoo \u003c- function() \"foo\"\n```\n\n**main.R**\n\n\n```r\nm \u003c- modules::use(\"module.R\")\nm$foo()\n```\n\n```\n## [1] \"foo\"\n```\n\nThe two examples illustrate the two ways in which modules can be constructed.\nSince modules are isolated from the `.GlobalEnv` the following object `x` can\nnot be found:\n\n\n```r\nx \u003c- \"hey\"\nm \u003c- module({\n  someFunction \u003c- function() x\n})\nm$someFunction()\n```\n\n```\n## Error in m$someFunction(): object 'x' not found\n```\n\n```r\ngetSearchPathContent(m)\n```\n\n```\n## List of 4\n##  $ modules:root     : chr \"someFunction\"\n##  $ modules:internals: chr [1:9] \"attach\" \"depend\" \"export\" \"expose\" ...\n##  $ base             : chr [1:1244] \"-\" \"-.Date\" \"-.POSIXt\" \":\" ...\n##  $ R_EmptyEnv       : chr(0) \n##  - attr(*, \"class\")= chr [1:2] \"SearchPathContent\" \"list\"\n```\n\nTwo features of modules are important at this point:\n\n- We can keep the global workspace clean, by introducing a local scope\n- We have no direct access to the global environment from modules by default,\nenforcing discipline when using any form of dependency (objects and packages)\n\nThe following subsections explain how to work with these two features.\n\n## Imports\n\nIf you rely on exported objects of a package you can refer to them explicitly\nusing `::`:\n\n\n```r\nm \u003c- module({\n  functionWithDep \u003c- function(x) stats::median(x)\n})\nm$functionWithDep(1:10)\n```\n\n```\n## [1] 5.5\n```\n\nOr you can use `import` for *attaching* single objects or packages. Import acts as a substitute for `library` with an important difference: `library` has the side effect of changing the search path of the complete R session. `import` only changes the search path of the calling environment, i.e. the side effect is local to the module and does not affect the global state of the R session.\n\n\n```r\nm \u003c- module({\n\n  import(\"stats\", \"median\") # make median from package stats available\n\n  functionWithDep \u003c- function(x) median(x)\n\n})\nm$functionWithDep(1:10)\n```\n\n```\n## [1] 5.5\n```\n\n```r\ngetSearchPathContent(m)\n```\n\n```\n## List of 5\n##  $ modules:root     : chr \"functionWithDep\"\n##  $ modules:stats    : chr \"median\"\n##  $ modules:internals: chr [1:9] \"attach\" \"depend\" \"export\" \"expose\" ...\n##  $ base             : chr [1:1244] \"-\" \"-.Date\" \"-.POSIXt\" \":\" ...\n##  $ R_EmptyEnv       : chr(0) \n##  - attr(*, \"class\")= chr [1:2] \"SearchPathContent\" \"list\"\n```\n\n\n```r\nm \u003c- module({\n\n  import(\"stats\")\n\n  functionWithDep \u003c- function(x) median(x)\n\n})\nm$functionWithDep(1:10)\n```\n\n```\n## [1] 5.5\n```\n\n## Importing modules\n\nTo *import* other modules, the function `use` can be called. *use* really just means *import module*. With `use` we can load modules:\n\n- defined in the calling environment of the module definition\n- or defined in files or folders (see the corresponding vignette on this topic)\n\nConsider the following example:\n\n\n```r\nmm \u003c- module({\n  m \u003c- use(m)\n  anotherFunction \u003c- function(x) m$functionWithDep(x)\n})\nmm$anotherFunction(1:10)\n```\n\n```\n## [1] 5.5\n```\n\nTo load modules from a file we can refer to the file directly:\n\n\n```r\nmodule({\n  m \u003c- use(\"someFile.R\")\n  # ...\n})\n```\n\n## Exports\n\nModules can help to isolate code from the state of the global environment. Now\nwe may have reduced the complexity in our global environment and moved it into a\nmodule. However, to make it very obvious which parts of a module should be used\nwe can also define exports. Every non-exported object will not be accessible.\n\nProperties of exports are:\n\n- You can list the names of objects in a call to `export`.\n- Exports stack up: you can have multiple calls to `export` in a module\ndefinition, i.e. directly in front of each function you want to export.\n- Exports can be defined as regular expressions which is indicated by a leading\n'^'. In this case only one export declaration should be used.\n\n\n```r\nm \u003c- module({\n\n  export(\"fun\")\n\n  fun \u003c- identity # public\n  privateFunction \u003c- identity\n\n  # .named are always private\n  .privateFunction \u003c- identity\n\n})\n\nm\n```\n\n```\n## fun:\n## function(x)\n```\n\n# Example: Modules as Parallel Process\n\nOne example where you may want to have more control of the enclosing environment\nof a function is when you parallelize your code. First consider the case when a\n*naive* implementation fails.\n\n\n```r\nlibrary(\"parallel\")\ndependency \u003c- identity\nfun \u003c- function(x) dependency(x)\n\ncl \u003c- makeCluster(2)\nclusterMap(cl, fun, 1:2)\n```\n\n```\n## Error in checkForRemoteErrors(val): 2 nodes produced errors; first error: could not find function \"dependency\"\n```\n\n```r\nstopCluster(cl)\n```\n\nTo make the function `fun` self contained we can define it in a module.\n\n\n```r\nm \u003c- module({\n  dependency \u003c- identity\n  fun \u003c- function(x) dependency(x)\n})\n\ncl \u003c- makeCluster(2)\nclusterMap(cl, m$fun, 1:2)\n```\n\n```\n## [[1]]\n## [1] 1\n## \n## [[2]]\n## [1] 2\n```\n\n```r\nstopCluster(cl)\n```\n\nNote that the parallel computing facilities in `R` always provide a way to\nhandle such situations. Here it is just a matter of organization if you believe\nthe function itself should handle its dependencies or the parallel interface.\n\n\n# Related Projects\n\nThere exist several projects with similar goals. First of all, the package\n[klmr/modules](https://github.com/klmr/modules) aims at providing a unit similar\nto what [Python](https://www.python.org/)-modules are. This project is obviously\ninteresting for you when you have prior knowledge in Python. `klmr/modules`\nmodules aim for a full replacement of R-packages. Otherwise there is\nconsiderable overlap of features between the two packages.\n\nSecond you may be interested in\n[import](https://cran.r-project.org/package=import) which provides convenient\nsyntax for stating dependencies in script files. This is something which is also\ncovered here, although, when you are only interested in a replacement for\n`library` the package `import` is more focused.\n\n`modules` in this package can act as objects as in object-orientation. In\ncontrast to [R6](https://cran.r-project.org/package=R6) and reference classes\nimplemented in the methods package here these objects are immutable by default.\nFurthermore it is not being made easy to change state of a module; but it is not\ndifficult to do that if you really want to: see the section on coupling below.\nFurthermore inheritance is not a feature, instead you have various possibilities\nfor object composition.\n\nThe development of the `modules` package has been inspired by other languages:\n[F#](https://fsharpforfunandprofit.com/posts/organizing-functions/),\n[Erlang](https://learnyousomeerlang.com/modules/) and\n[julia](https://docs.julialang.org/en/v1/manual/modules/index.html).\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwahani%2Fmodules","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwahani%2Fmodules","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwahani%2Fmodules/lists"}