{"id":17086439,"url":"https://github.com/dasch/option","last_synced_at":"2025-03-23T14:30:33.595Z","repository":{"id":14377972,"uuid":"17088080","full_name":"dasch/option","owner":"dasch","description":"An Erlang library for working with options","archived":false,"fork":false,"pushed_at":"2014-02-22T18:01:43.000Z","size":164,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-28T20:42:01.152Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dasch.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}},"created_at":"2014-02-22T15:57:39.000Z","updated_at":"2014-02-22T18:01:44.000Z","dependencies_parsed_at":"2022-08-27T03:24:35.839Z","dependency_job_id":null,"html_url":"https://github.com/dasch/option","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dasch%2Foption","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dasch%2Foption/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dasch%2Foption/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dasch%2Foption/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dasch","download_url":"https://codeload.github.com/dasch/option/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245115464,"owners_count":20563171,"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":[],"created_at":"2024-10-14T13:28:39.063Z","updated_at":"2025-03-23T14:30:33.546Z","avatar_url":"https://github.com/dasch.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"Options in Erlang\n=================\n\nOptions are structures that contain either one or no value. They're useful if a function may not be able to return a value. As an example, consider a function that parses a string, returning a stock keeping unit (SKU) identifier in the format `SKUXXX-XXX` if one can be found:\n\n```erlang\nscan_sku_identifier(Text) -\u003e\n  Regex = \"SKU\\\\d{3}-\\\\d{3}\",\n  case re:run(Text, Regex) of\n    {match, [{Start, Length}]} -\u003e string:substr(Text, Start + 1, Length);\n    nomatch                    -\u003e none\n  end.\n```\n\nThis function returns either the SKU identifier, or `none` if no such identifier could be found. The problem is that users of this function have to remember to deal with the `none` case:\n\n```erlang\ncase scan_sku_identifier(Text) of\n  none -\u003e some_error;\n  SKU  -\u003e continue_doing_stuff(SKU)\nend.\n```\n\nMost likely, though, they'll forget it and just write:\n\n```erlang\nSKU = scan_sku_identifier(Text).\n```\n\nIf `Text` doesn't contain a valid SKU, the `SKU` variable will be bound to the atom `none`, and the program will continue. This is obviously bad – you want the program to fail close to the location of the bug.\n\nThe solution is to force the user to deal with the fact that the function does not return the SKU itself, but rather the _option_ of a SKU, meaning it might not return any value at all. The updated implementation will look like this:\n\n\n```erlang\nscan_sku_identifier(Text) -\u003e\n  Regex = \"SKU\\\\d{3}-\\\\d{3}\",\n  case re:run(Text, Regex) of\n    {match, [{Start, Length}]} -\u003e {ok, string:substr(Text, Start + 1, Length)};\n    nomatch                    -\u003e none\n  end.\n```\n\nThe user can now choose to deal with the error explicitly or not. If she expects there to always be a SKU in the string, she can write the code thus:\n\n```erlang\n{ok, SKU} = scan_sku_identifier(Text).\n```\n\nIf, due to some bug, there isn't one anyway, an error will be raised at the location of the bug. Additional error handling can then be added to handle the case more gracefully:\n\n```erlang\ncase scan_sku_identifier(Text) of\n  {ok, SKU} -\u003e continue_doing_stuff(SKU);\n  none      -\u003e deal_with_the_error()\nend.\n```\n\nThe point being that the bug was much easier to find.\n\nThis is a fairly common pattern in Erlang. The point of this library is to provide some high level functions for dealing with options. For instance, say you wish to extract the SKUs from a list of strings, disregarding the strings that contain no SKUs. Using the `option` module, it's trivial:\n\n```erlang\nTexts = [\"Product code: SKU123-456.\", \"Refrigerator\", \"This is SKU666-666!\"],\nSkuOptions = lists:map(fun scan_sku_identifier/1, Texts),\n[\"SKU123-456\", \"SKU666-666\"] = option:select(SkuOptions).\n```\n\n`option:select` takes care of extracting the values and removing the none options.\n\nAnother common pattern is when, if an option is none, a default value should be used. `option:default/2` makes this easy:\n\n```erlang\n\"SKU123-456\" = option:default(scan_sku_identifier(\"Product: SKU123-456\"), \"N/A\"),\n\"N/A\" = option:default(scan_sku_identifier(\"Microwave oven\"), \"N/A\").\n```\n\n\nUsage\n-----\n\nAny tuple `{ok, X}` will be considered an ok option with the value `X` – anything else is a none option.\n\n- `option:select/1` extracts the ok values from a list of options.\n- `option:value/1` extracts the ok value from a single argument, raising an error if it is none.\n- `option:default/2` extracts the ok value from a single argument, returning a default value if the argument is none.\n\n\nCopyright\n---------\n\nCopyright (c) 2014 Daniel Schierbeck\n\nLicensed under the [MIT license](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdasch%2Foption","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdasch%2Foption","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdasch%2Foption/lists"}