{"id":20163720,"url":"https://github.com/emik03/emik.sourcegenerators.thesquarehole","last_synced_at":"2026-02-18T15:01:04.961Z","repository":{"id":189819420,"uuid":"676694053","full_name":"Emik03/Emik.SourceGenerators.TheSquareHole","owner":"Emik03","description":"Adds structural typing to C#.","archived":false,"fork":false,"pushed_at":"2025-01-01T10:51:52.000Z","size":585,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-25T23:55:15.415Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Emik03.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"Emik03","custom":"https://paypal.me/emik03"}},"created_at":"2023-08-09T19:41:49.000Z","updated_at":"2025-01-01T10:51:56.000Z","dependencies_parsed_at":"2025-10-11T02:32:32.034Z","dependency_job_id":"56008b77-5b23-44b1-bf4a-f3615e404b2e","html_url":"https://github.com/Emik03/Emik.SourceGenerators.TheSquareHole","commit_stats":null,"previous_names":["emik03/emik.sourcegenerators.thesquarehole"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Emik03/Emik.SourceGenerators.TheSquareHole","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Emik03%2FEmik.SourceGenerators.TheSquareHole","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Emik03%2FEmik.SourceGenerators.TheSquareHole/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Emik03%2FEmik.SourceGenerators.TheSquareHole/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Emik03%2FEmik.SourceGenerators.TheSquareHole/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Emik03","download_url":"https://codeload.github.com/Emik03/Emik.SourceGenerators.TheSquareHole/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Emik03%2FEmik.SourceGenerators.TheSquareHole/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29582790,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-18T13:56:48.962Z","status":"ssl_error","status_checked_at":"2026-02-18T13:54:34.145Z","response_time":162,"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":[],"created_at":"2024-11-14T00:31:19.762Z","updated_at":"2026-02-18T15:01:04.944Z","avatar_url":"https://github.com/Emik03.png","language":"C#","funding_links":["https://github.com/sponsors/Emik03","https://paypal.me/emik03"],"categories":[],"sub_categories":[],"readme":"# Emik.SourceGenerators.TheSquareHole\n\n[![NuGet package](https://img.shields.io/nuget/v/Emik.SourceGenerators.TheSquareHole.svg?logo=NuGet)](https://www.nuget.org/packages/Emik.SourceGenerators.TheSquareHole)\n[![License](https://img.shields.io/github/license/Emik03/Emik.SourceGenerators.TheSquareHole.svg?style=flat)](https://github.com/Emik03/Emik.SourceGenerators.TheSquareHole/blob/main/LICENSE)\n\n\u003cblockquote\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/Emik03/Emik.SourceGenerators.TheSquareHole/main/Images/icon.png\" alt=\"icon.png\" width=\"50\"/\u003e\n    \u0026emsp;\n    \u003ca href=\"https://youtu.be/Nz8ssH7LiB0?t=22\"\u003e\n       \"And up next, a cylinder. Hmm, I think that goes in... the square hole!\"\n    \u003c/a\u003e\n\u003c/blockquote\u003e\n\nAdds structural typing to C#. Made as a celebration for my 20th birthday on August 8th 2023.\n\nThis project has a dependency to [Emik.Morsels](https://github.com/Emik03/Emik.Morsels), if you are building this project, refer to its [README](https://github.com/Emik03/Emik.Morsels/blob/main/README.md) first.\n\n---\n\n- [Why](#why)\n- [How](#how)\n- [Configure](#configure)\n- [Contribute](#contribute)\n- [License](#license)\n\n---\n\n## Why\n\nDespite the presentation of the project, the project itself is treated very seriously and addresses a real-world problem.\n\nWhen creating software, you are encouraged to write code that is easily extensible and reusable. Interfaces are a fantastic way of achieving this, often allowing you to reuse methods that take said interface as a parameter. Part of the problem however is having to juggle the signatures of each interface in your head.\n\nIf you are creating a type specifically to implement an interface, this isn't much of a problem, but if you want to maximize the re-usability of a type, particularly if you make a type whose purpose is fairly generic, then you may often sit thinking about each interface you may consider adding.\n\nLanguages like Scala solve this issue using Structural Typing. If a type has the same declaring members as an interface, then it derives it.\n\n## How\n\nThis source generator looks at every interface accessible from your assembly and determines whether it is able to implement the interface.\n\nEmpty interfaces, alongside attributes marked with [`ObsoleteAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.obsoleteattribute?view=net-7.0) are **not considered part of the search**, as these interfaces tend to function more like attributes, and should therefore be opt-in.\n\nIf the interface contains generics, then the source generator performs **Type Substitution**: It considers every type declared within any type, including itself. For instance, take a look at the following type:\n\n```csharp\npublic class A(int i);\n```\n\nThe type `A` declares a method with a parameter `int`, with nothing else. Therefore the candidates are `int` and `A`.\n\nThis results in the source generator being extremely flexible, and accounts for every possible implementation. For instance:\n\n```csharp\npublic partial record Cylinder\u003cT1, T2\u003e(T1 Second)\n{\n    public int First =\u003e 0;\n}\n\ninterface ISquare\u003cout T1, out T2\u003e\n{\n    T1 First { get; }\n\n    T2 Second { get; }\n}\n```\n\n...generates...\n\n```csharp\n// \u003cauto-generated/\u003e\n#nullable enable\npartial record Cylinder\u003cT1, T2\u003e : global::ISquare\u003cint, T1\u003e,\n    global::System.Numerics.IEqualityOperators\u003cglobal::Cylinder\u003cT1, T2\u003e, global::Cylinder\u003cT1, T2\u003e, bool\u003e\n{\n}\n```\n\nThe hard upper limit for type substitution with generics are exactly **3** of them. This does not include generics which are self-constrained.\n\nWhile this analyzer does perform a lot of tricks to squeeze performance, type substituion may be still too expensive on your machine. Refer to [Configure](#configure) in that case.\n\n## Configure\n\nUse `.editorconfig`/`.globalconfig` to configure this source generator:\n\n---\n\n| Option   | `the_square_hole_enable_concurrency`                                                                                                                                                                                                                                                                                                  |\n|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| Summary  | Determines whether to enable concurrency for inspections.                                                                                                                                                                                                                                                                             |\n| Remarks  | Concurrency is only faster in large projects due to overhead in initializing concurrent behavior, hence why it's disabled by default.                                                                                                                                                                                                 |\n| Obsolete | This option is deprecated starting from `1.1` and onwards due to the migration of the favorable [`IIncrementalGenerator`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.iincrementalgenerator) over [`ISourceGenerator`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.isourcegenerator). |\n| Type     | `bool`                                                                                                                                                                                                                                                                                                                                |\n| Default  | `false`                                                                                                                                                                                                                                                                                                                               |\n\n---\n\n| Option  | `the_square_hole_include_nullability`                                                                                                                                                                                                                                    |\n|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| Summary | Determines whether or not to include nullability as a restriction.                                                                                                                                                                                                       |\n| Remarks | `A(string s)` and `A(string? s)` are equal interface-wise despite the unequal signature metadata. This can however violate the contract of the interface, and you will get the suggestion to change the signature, which would be a breaking feature in an existing API. |\n| Type    | `bool`                                                                                                                                                                                                                                                                   |\n| Default | `false`                                                                                                                                                                                                                                                                  |\n\n---\n\n| Option  | `the_square_hole_include_parameter_name`                                                                                                                                                                                 |\n|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| Summary | Determines whether or not to include parameter names as a restriction.                                                                                                                                                   |\n| Remarks | `A(int a)` and `A(int b)` are equal interface-wise despite the unequal parameter naming. Some analyzers encourage renaming parameters when such a scenario occurs, which would be a breaking feature in an existing API. |\n| Type    | `bool`                                                                                                                                                                                                                   |\n| Default | `false`                                                                                                                                                                                                                  |\n\n---\n\n| Option  | `the_square_hole_max_substitution_depth`                                                        |\n|---------|-------------------------------------------------------------------------------------------------|\n| Summary | Determines the maximum number of type substitutions allowed for a given interface.              |\n| Remarks | Lower = faster, higher = better inference of generics. Lower it if you face performance issues. |\n| Type    | `0..=3`                                                                                         |\n| Default | `3`                                                                                             |\n\n---\n\n## Contribute\n\nIssues and pull requests are welcome to help this repository be the best it can be.\n\n## License\n\nThis repository falls under the [MPL-2 license](https://www.mozilla.org/en-US/MPL/2.0/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femik03%2Femik.sourcegenerators.thesquarehole","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femik03%2Femik.sourcegenerators.thesquarehole","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femik03%2Femik.sourcegenerators.thesquarehole/lists"}