{"id":22375865,"url":"https://github.com/stylewarning/interface","last_synced_at":"2026-01-06T10:33:44.274Z","repository":{"id":236852844,"uuid":"625691879","full_name":"stylewarning/interface","owner":"stylewarning","description":null,"archived":false,"fork":false,"pushed_at":"2023-04-09T22:35:00.000Z","size":12,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-25T23:34:10.570Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stylewarning.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-04-09T22:08:08.000Z","updated_at":"2024-10-01T05:43:44.000Z","dependencies_parsed_at":"2024-04-29T00:08:22.459Z","dependency_job_id":"bebb0e61-c218-42d6-b6a0-fd7e675741ec","html_url":"https://github.com/stylewarning/interface","commit_stats":null,"previous_names":["stylewarning/interface"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stylewarning%2Finterface","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stylewarning%2Finterface/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stylewarning%2Finterface/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stylewarning%2Finterface/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stylewarning","download_url":"https://codeload.github.com/stylewarning/interface/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245708990,"owners_count":20659625,"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-12-04T21:28:01.738Z","updated_at":"2026-01-06T10:33:39.256Z","avatar_url":"https://github.com/stylewarning.png","language":"Common Lisp","funding_links":[],"categories":[],"sub_categories":[],"readme":"# INTERFACE\n\nBy Robert Smith\n\n## Introduction\n\nThis system contains an implementation of interfaces and\nimplementations. They're sometimes called protocols in other\nlanguages.\n\nBroadly speaking, an \"interface\" is some collection of function\n\"prototypes\" that a valid implementation must implement. For example,\nsomething called a \"stack\" must implement stack creation, pushing,\npeeking, and popping.\n\nThe notion of interfaces and implementations aid the distinction\nbetween data structures and different implementations of that data\nstructure. This was perhaps pioneered by Modula-3, and became a\nsignificant part of other languages like Standard ML and OCaml. In all\nof the aforementioned languages, interfaces can actually contain more\nthan just functions, such as types and values. Haskell typeclasses are\nalso a form of interface and implementation. They are very general and\nare even parametric.\n\nOne way to accomplish the notion of interfaces and implementations in\nLisp is to use some \"abstract class\" and make several (final)\nsubclasses of that class. The interface, in this case, is the abstract\nclass and a collection of generic functions. The implementation would\nbe the final subclass along with method definitions.\n\nFor example:\n\n```lisp\n(defclass stack () ())\n(defgeneric make-stack (impl))\n(defgeneric stack-push (impl s x))\n(defgeneric stack-pop (impl s))\n(defgeneric stack-peek (impl s))\n\n(defclass list-stack (stack) ())\n(defmethod make-stack ((impl list-stack))\n  nil)\n(defmethod stack-push ((impl list-stack) s x)\n  (cons x s))\n(defmethod stack-pop ((impl list-stack) s)\n  (cdr s))\n(defmethod stack-peek ((impl list-stack) s)\n  (car s))\n```\n\nThis is mostly sufficient, though Lisp makes no guarantee that a class\nwill have any set of methods defined for it. (One could perhaps use\nthe MOP for this.) One can \"optimize\" implementations by conflating\nthe notion of an implementation with the actual data structure being\nimplemented, and make it a part of the implementation class. In this\ncase, we could have a slot in `LIST-STACK` holding the list.\n\nSince methods are not tied to classes, this implementation allows one\nto have a class implement several methods. Also, it is entirely\npossible to do away with the superclass; that is a formality tying all\nimplementations to a particular interface with a name.\n\nAs I understand, this basic notion is taken to the extreme with Fare's\n[Lisp Interface Library](http://www.cliki.net/lisp-interface-library).\n\nIn this system, however, we take a different approach\nentirely. Instead of using a class to represent interfaces and\nimplementations, we have a structure whose slots are the\nimplementation functions. The name of the structure (which decides\nwhat slots it has) is the interface, and the implementation is the\nactual slot values.\n\nIt is cumbersome, however, to use an interface by accessing slots all\nof the time. Instead, we define functions---which correspond to the\nslot names---which access the slots of an implementation and pass the\narguments to it.\n\nIn doing this, there's no dispatch on type required, just access on\nthe slots of the structure. It also forces data structures and the\ninterface to be completely disjoint entities.\n\n\n## Example\n\n```lisp\n(define-interface stack ()\n  (make-stack (\u0026rest r))\n  (push-stack (s x))\n  (peek-stack (s))\n  (pop-stack (s)))\n\n(define-implementation list-stack (stack)\n  :make-stack\n  (lambda (\u0026rest r)\n    r)\n\n  :push-stack\n  (lambda (s x)\n    (cons x s))\n\n  :peek-stack\n  (lambda (s)\n    (car s))\n  \n  :pop-stack\n  (lambda (s)\n    (cdr s)))\n\n(define-implementation vector-stack (stack)\n  :make-stack\n  (lambda (\u0026rest r)\n    (let ((length (length r)))\n      (make-array length\n                  :adjustable t\n                  :fill-pointer length\n                  :initial-contents r)))\n  \n  :push-stack\n  (lambda (s x)\n    (vector-push-extend x s)\n    s)\n  \n  :peek-stack\n  (lambda (s)\n    (aref s (1- (length s))))\n  \n  :pop-stack\n  (lambda (s)\n    (vector-pop s)\n    s))\n\n;;; CL-USER\u003e (pop-stack vector-stack\n;;;                     (push-stack vector-stack\n;;;                                 (make-stack vector-stack 1 2 3)\n;;;                                 5))\n;;; #(1 2 3)\n;;; CL-USER\u003e (pop-stack list-stack\n;;;                     (push-stack list-stack\n;;;                                 (make-stack list-stack 1 2 3)\n;;;                                 5))\n;;; (1 2 3)\n```\n\n## Performance\n\nThis implementation has been measured to be between 10% and 30% faster\nthan the classes approach described above. See the file\n`interface-bench.lisp`.\n\n## Other notes\n\nThe package also has a handy utility function called\n`CALLING-FORM`. It solves the following problem:\n\nConsider a function `F` with a lambda list `(L...)`. How can we write\na function `G`\n\n```lisp\n(defun G (L...)\n  \u003c???\u003e)\n```\n\nsuch that calls to `G` are precisely equivalent to `F`? We can use\n\n```lisp\n(calling-form 'f '(L...))\n```\n\nwhich will produce code which is suitable for the definition of `G`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstylewarning%2Finterface","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstylewarning%2Finterface","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstylewarning%2Finterface/lists"}