{"id":13857616,"url":"https://github.com/jonthegeek/factory","last_synced_at":"2025-03-21T13:30:59.533Z","repository":{"id":56936750,"uuid":"182615532","full_name":"jonthegeek/factory","owner":"jonthegeek","description":"factory: Build Function Factories","archived":false,"fork":false,"pushed_at":"2020-06-04T22:42:24.000Z","size":207,"stargazers_count":49,"open_issues_count":14,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-18T01:42:38.914Z","etag":null,"topics":["function-factory","r"],"latest_commit_sha":null,"homepage":"","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/jonthegeek.png","metadata":{"files":{"readme":"README.Rmd","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-04-22T03:19:20.000Z","updated_at":"2024-10-10T15:20:25.000Z","dependencies_parsed_at":"2022-08-21T01:10:28.215Z","dependency_job_id":null,"html_url":"https://github.com/jonthegeek/factory","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonthegeek%2Ffactory","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonthegeek%2Ffactory/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonthegeek%2Ffactory/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonthegeek%2Ffactory/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jonthegeek","download_url":"https://codeload.github.com/jonthegeek/factory/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244806063,"owners_count":20513370,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["function-factory","r"],"created_at":"2024-08-05T03:01:42.043Z","updated_at":"2025-03-21T13:30:59.268Z","avatar_url":"https://github.com/jonthegeek.png","language":"R","funding_links":[],"categories":["R"],"sub_categories":[],"readme":"---\noutput: github_document\n---\n\n\u003c!-- README.md is generated from README.Rmd. Please edit that file --\u003e\n\n```{r, include = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#\u003e\",\n  fig.path = \"man/figures/README-\",\n  out.width = \"100%\"\n)\n```\n# factory \u003cimg src='man/figures/factory.png' align=\"right\" height=\"138.5\" /\u003e\n\n\u003c!-- badges: start --\u003e\n[![Lifecycle: maturing](https://img.shields.io/badge/lifecycle-maturing-blue.svg)](https://www.tidyverse.org/lifecycle/#maturing)\n[![Travis build status](https://travis-ci.org/jonthegeek/factory.svg?branch=master)](https://travis-ci.org/jonthegeek/factory)\n[![AppVeyor build status](https://ci.appveyor.com/api/projects/status/github/jonthegeek/factory?branch=master\u0026svg=true)](https://ci.appveyor.com/project/jonthegeek/factory)\n[![Codecov test coverage](https://codecov.io/gh/jonthegeek/factory/branch/master/graph/badge.svg)](https://codecov.io/gh/jonthegeek/factory?branch=master)\n[![CRAN status](https://www.r-pkg.org/badges/version/factory)](https://CRAN.R-project.org/package=factory)\n\u003c!-- badges: end --\u003e\n\nThe goal of factory is to make construction of function factories more straightforward, without requiring the user to learn the `rlang` package.\n\n## Installation\n\nInstall the released version of factory from CRAN:\n\n```{r cran, eval = FALSE}\ninstall.packages(\"factory\")\n```\n\nOr install the development version from [GitHub](https://github.com/jonthegeek/factory) with:\n\n```{r dev, eval = FALSE}\n# install.packages(\"remotes\")\nremotes::install_github(\"jonthegeek/factory\")\n```\n\n## Motivation\n\nFunction factories are functions that make functions. \nThey can be confusing to work with. \nFor example, as we'll see below, they can produce functions that are fragile, or that are confusing to work with as a user.\n\nWARNING: All code shown below is \"wrong\" in some way until we get to the example at the end! These examples show the dangers of working with function factories, and why this package exists.\n\n(examples adapted from [Advanced R by Hadley Wickham (2nd Edition), 10.2.3: Forcing Evaluation](https://adv-r.hadley.nz/function-factories.html#forcing-evaluation))\n\n### The Simplest Factories are Fragile\n\n`power1` is a function factory. \nIt returns a function based on the `exponent` argument.\n\n```{r power1}\npower1 \u003c- function(exponent) {\n  function(x) {\n    x ^ exponent\n  }\n}\n```\n\nFor many use cases, `power1` works fine.\nFor example, we can define a square function by calling `power1` with `exponent = 2`.\n\n```{r power1-simple-usage}\nsquare1 \u003c- power1(2)\nsquare1(2)\n# 2 ^ 2 = 4\nsquare1(3)\n# 3 ^ 2 = 9\n```\n\nHowever, `power1` is fragile. \nLet's think about what the definition of power1 *means.* \nThe function returned by `power1` raises its argument to whatever the `exponent` variable is defined as.\nLet's see what happens if we use a variable in the global environment to define our `square` function.\n\n```{r power1-fragile}\nmy_exponent \u003c- 2\nsquare1a \u003c- power1(my_exponent)\n```\n\nDue to R's lazy evaluation, when we call `power1`, the `exponent` variable gets a promise to take on the value of the `my_exponent` variable.\nBut `my_exponent` doesn't actually have the value of `2` yet.\nUntil we *use* `my_exponent`, it has a *promise* to get the value of `2`.\nIf we call `square1a` right away, it works as expected.\n\n```{r power1-fragile-seems-ok}\nsquare1a(2)\n# 2 ^ 2 = 4\nmy_exponent \u003c- 3\nsquare1a(3)\n# 3 ^ 2 = 9\n```\n\nThe `my_exponent` promise (which was passed in during the definition of `square1a`) resolves to `2` the first time it is needed (when `square1a` is first called). \nAfter that initial call, that is the value used in `square1a` forever.\n\nBut if `my_exponent` changes between definition of our function and first call of that function, we get a different result.\n\n```{r power1-fragile-breaks}\nmy_exponent \u003c- 2\nsquare1b \u003c- power1(my_exponent)\nmy_exponent \u003c- 3\nsquare1b(2)\n# 2 ^ 3 = 8\nsquare1b(3)\n# 3 ^ 3 = 27\n```\n\nWhat happened? \nWhen `square1b` was defined, `my_exponent` was passed in as a *promise.* \nHowever, before `my_exponent` was ever actually *used*, its value changed.\nThe promise isn't evaluated *until it is used,* which, in this case, is the first time `square1b` is called.\nOnce the promise is evaluated, its value is \"fixed,\" and the function works as expected.\n\n### Forcing Arguments Trades Fragility for Complexity\n\nWe can make factories that are less fragile, if we remember to `force` the variables.\n\n```{r power2}\npower2 \u003c- function(exponent) {\n  force(exponent) # Gah, easy to forget!\n  function(x) {\n    x ^ exponent\n  }\n}\n\nmy_exponent \u003c- 2\nsquare2 \u003c- power2(my_exponent)\nmy_exponent \u003c- 3\nsquare2(2)\n# 2 ^ 2 = 4\nsquare2(3)\n# 3 ^ 2 = 9\n```\n\nWhy does this work?\nThe `force` function forces the evaluation of its argument.\nWe don't really need to use `force`, per se. \nAny function that forces evaluation would work, but `force` makes it obvious why we're doing it.\nFor example, we could produce the same result by `message`ing within the factory.\n\n```{r power2-message}\npower2b \u003c- function(exponent) {\n  message(\"The exponent's value is \", exponent)\n  function(x) {\n    x ^ exponent\n  }\n}\n\nmy_exponent \u003c- 2\nsquare2b \u003c- power2b(my_exponent)\nmy_exponent \u003c- 3\nsquare2b(2)\n# 2 ^ 2 = 4\nsquare2b(3)\n# 3 ^ 2 = 9\n```\n\nSince the value of `exponent` is needed for the message, the promise is evaluated when the factory is invoked, and the resulting function is stable.\n\nWhile such factories are more stable, it's easy to miss a `force`.\nAnd, in both of these cases, the resulting functions are difficult to understand as a user.\n\n```{r resulting-functions}\nsquare1\nsquare2\ncube \u003c- power2(3)\ncube\n```\n\nIt isn't clear what these functions will do, since the definitions of `exponent` are hidden inside the function environments.\n\n### Using rlang\n\nWe can use {rlang} to make functions that are easier to understand, but building the function factory is much more difficult (from [Advanced R by Hadley Wickham (2nd Edition), 19.7.4: Creating functions](https://adv-r.hadley.nz/quasiquotation.html#new-function)): \n\n```{r power3}\npower3 \u003c- function(exponent) {\n  rlang::new_function(\n    rlang::exprs(x = ), \n    rlang::expr({\n      x ^ !!exponent\n    }), \n    rlang::caller_env()\n  )\n}\n```\n\nThe resulting functions look like a \"normal\" function, though, and are thus easier for users to understand.\n\n```{r square3}\nsquare3 \u003c- power3(2)\nsquare3\n```\n\nThe {rlang} calls are very difficult to understand, though.\nIt would be nice to get the stability and interpretability of the rlang-produced functions, with the ease-of-programming of the simplest function factories.\n\n\n## Enter {factory}\n\nThe goal of `factory` is to make function factories as straightforward to create as in `power1`, but to make the resulting functions make as much sense as in `power3`.\nRight now, the calls are still a *little* more complicated than I would like, but they're definitely easier to understand than the {rlang} calls.\n\n```{r power4}\nlibrary(factory)\npower4 \u003c- build_factory(\n  fun = function(x) {\n    x ^ exponent\n  },\n  exponent\n)\n\nmy_exponent \u003c- 2\nsquare4 \u003c- power4(my_exponent)\nmy_exponent \u003c- 3\nsquare4(2)\n# 2 ^ 2 = 4\n```\n\nThe resulting function makes sense, as with `power3`.\n\n```{r square4}\nsquare4\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonthegeek%2Ffactory","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonthegeek%2Ffactory","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonthegeek%2Ffactory/lists"}