{"id":16880626,"url":"https://github.com/squaremo/js-pmd","last_synced_at":"2025-08-12T09:09:57.380Z","repository":{"id":5811806,"uuid":"7026770","full_name":"squaremo/js-pmd","owner":"squaremo","description":"Multiple dispatch for JavaScript (toy implementation)","archived":false,"fork":false,"pushed_at":"2013-02-23T07:48:07.000Z","size":144,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-11T12:13:24.759Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/squaremo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-12-05T23:48:13.000Z","updated_at":"2022-08-30T01:37:36.000Z","dependencies_parsed_at":"2022-08-31T16:51:56.020Z","dependency_job_id":null,"html_url":"https://github.com/squaremo/js-pmd","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/squaremo/js-pmd","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/squaremo%2Fjs-pmd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/squaremo%2Fjs-pmd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/squaremo%2Fjs-pmd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/squaremo%2Fjs-pmd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/squaremo","download_url":"https://codeload.github.com/squaremo/js-pmd/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/squaremo%2Fjs-pmd/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270033270,"owners_count":24515465,"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","status":"online","status_checked_at":"2025-08-12T02:00:09.011Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2024-10-13T15:59:33.468Z","updated_at":"2025-08-12T09:09:57.349Z","avatar_url":"https://github.com/squaremo.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Multiple dispatch in JavaScript\n\nThis module implements generic functions, for JavaScript, using the\n\u003cdef\u003ePrototype Multiple Dispatch\u003c/def\u003e algorithm as described in\n\u003chttp://lee.fov120.com/ecoop.pdf\u003e. I'm writing it to see how\nprogramming in JavaScript with generic functions works out.\n\n## What are generic functions?\n\nA generic function is a family of procedures (I'm using \"procedure\" to\ndistinguish the family members from the family itself, but think of\nthem as regular functions), of which one is selected to be run for a\ngiven invocation. The particular procedure that will run depends on\nthe types of the arguments; each of the procedures in the family is\ncalled a \"method\".\n\nThis is like methods in JavaScript -- if I say `foo.frobnicate(bar)`,\nit's the `frobnicate` belonging to `foo`, or somewhere on its\nprototype chain, that is called. You could see all methods called\n`frobnicate` as being in a family, with the particular method run\ndepending on what appears before the dot when `frobnicate` is\ninvoked. With generic functions, though, the method run can depend on\nany or all of the arguments; each method belongs to all its arguments,\nnot just the first one. This is usually called \"multiple dispatch\", as\nopposed to the \"single dispatch\" of JavaScript (also Java, Smalltalk,\nand others).\n\nOne consequence of methods not belonging to a single value is that you\nhave to define them outside of values, and that leads to a more openly\nextensible system. For example, say I have a widget type that renders\na value differently depending on what kind of value it is (please\nexcuse poor jqueryism here, and let's pretend the value is boxed):\n\n    Widget.prototype.render = function(value) {\n      if (val instanceof String) {\n        this.append($('\u003cinput class=\"str\"/\u003e').val(value));\n      }\n      else if (value instanceof Boolean) {\n        this.append($('\u003cinput type=\"checkbox\"/\u003e').selected(value));\n      }\n      // ...\n    };\n\nIn some other file, I introduce my own kind of value that's specific\nto my application, and which I want to render its own specific\nway. Now I have a quandary. I could change my `widget.render`, adding\nanother `else if` for my new kind of value. This doesn't seem very\nsatisfactory, at best.\n\nAlternatively, I could rewrite `widget.render` use what's called\ndouble dispatch; that is, instead of checking the type of the value,\nit calls a method on the value:\n\n    Widget.prototype.render = function(value) {\n      this.append(value.toInput());\n    };\n\nThis way the code particular to my new kind of value can be given\nalong with it. However, now the code for `String`s and `Boolean`s also\nhas to go with them too; again, not very satisfactory. (This conundrum\nis akin to the [Expression\nProblem](http://en.wikipedia.org/wiki/Expression_problem). I say\n\"akin\" because we're not trying to keep type safety here, just to not\nfling code everywhere).\n\nIf `render` were a generic function, I could just add another method,\nalongside my new type, without disturbing any other `render` methods,\nor `String` and `Boolean`. Something like this:\n \n    render.method(Widget, MyValue, function(widget, value) {\n      var opts = $('\u003cselect class=\"myval\"/\u003e');\n      // ...\n      widget.append(opts);\n    });\n\n\n## Example\n\nThe general pattern is to create a procedure then add methods\nspecialising it. Methods may specialise in any argument to\nconstructors or values. When invoked, the procedure chooses the most\nspecific method given the arguments and applies it.\n\n```javascript\nvar procedure = require('./index');\n\n// Create a generic function\nvar print = procedure('print');\n\n// Specialise\nprint.method(Object, function (a) { return 'ANY: ' + a.toString(); });\nprint.method(Number, function (n) { return 'NUM: ' + n; });\nprint.method(3, function (three) { return 'MAGIC NUM'; });\n\n// print can be used like a regular function\nprint(3);\n// =\u003e 'MAGIC NUM'\nprint(17);\n// =\u003e 'NUM: 17'\nprint(true);\n// =\u003e 'ANY: true'\n```\n\n(By the way, the argument to `procedure` is really just to make nicer\nsymbols for debugging, but it may become important if the machinery is\nmore exposed in the future.)\n\n## Adaption to JavaScript\n\nThe model given in the paper is parameterised, so that it can be\nadapted to languages other than Slate for which it was designed.\n\nOne variable is the way in which the most applicable method is chosen\ngiven a list of arguments. I mimic Slate in ordering methods by the\n'closeness' (least distance in the delegation chain) of the first\nargument, then in the case of a tie, the second argument, and so on.\n\nAnother variable is how the delegation chain is determined (this ties\ninto the notion of 'closeness' above). In JavaScript, delegation is\nthrough an object's [[prototype]] (non-standardly available as the\nproperty `__proto__`). The [[prototype]] is supplied either as the\nargument to `Object.create(proto)`, or implicitly via the constructor\nfunction's `prototype` property.\n\nThis gives us the ability to specialise on values by using the\nprototypes themselves, or on types by using the `prototype` property\nof the constructor. In general, using `Object.create()` would lead to\nthe first kind of specialisation, and using the `new` operator would\nlead to the second.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsquaremo%2Fjs-pmd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsquaremo%2Fjs-pmd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsquaremo%2Fjs-pmd/lists"}