diff options
| author | Yong He <yonghe@outlook.com> | 2024-09-04 13:25:37 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-09-04 13:25:37 -0700 |
| commit | ddd29057e48a5b309726750e3daf78bfd073038e (patch) | |
| tree | a054b99acb87d61ef4818dce5fa837ccfd050288 /docs | |
| parent | 56a3c028a6725e13a2ae3a724eaee05ad9f4802a (diff) | |
Fix extension override behavior, and disallow extension on interface types. (#4977)
* Add a test to ensure extension does not override existing conformance.
* Fix doc.
* Update documentation.
* Fix doc.
* Add diagnostic test.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/user-guide/06-interfaces-generics.md | 51 |
1 files changed, 28 insertions, 23 deletions
diff --git a/docs/user-guide/06-interfaces-generics.md b/docs/user-guide/06-interfaces-generics.md index 982b2ba8b..569b36e1d 100644 --- a/docs/user-guide/06-interfaces-generics.md +++ b/docs/user-guide/06-interfaces-generics.md @@ -742,7 +742,8 @@ See [if-let syntax](convenience-features.html#if_let-syntax) for more details. Extensions to Interfaces ----------------------------- -In addition to extending ordinary types, you can define extensions on interfaces as well: +In addition to extending ordinary types, you can define extensions on all types that conforms to some interface: + ```csharp // An example interface. interface IFoo @@ -750,9 +751,8 @@ interface IFoo int foo(); } -// Extending `IFoo` with a new method requirement -// with a default implementation. -extension IFoo +// Extend any type `T` that conforms to `IFoo` with a `bar` method. +extension<T:IFoo> T { int bar() { return 0; } } @@ -765,42 +765,47 @@ int use(IFoo foo) } ``` -Although the syntax of above listing suggests that we are extending an interface with additional requirements, this interpretation does not make logical sense in many ways. Consider a type `MyType` that exists before the extension is defined: -```csharp -struct MyType : IFoo -{ - int foo() { return 0; } -} -``` +Note that `interface` types cannot be extended, because extending an `interface` with new requirements would make all existing types that conforms +to the interface no longer valid. -If we extend the `IFoo` with new requirements, the existing `MyType` definition would become invalid since `MyType` no longer provides implementations to all interface requirements. Instead, what an `extension` on an interface `IFoo` means is that for all types that conforms to the `IFoo` interface and does not have a `bar` method defined, add a `bar` method defined in this extension to that type so that all `IFoo` typed values have a `bar` method defined. If a type already defines a matching `bar` method, then the existing method will always override the default method provided in the extension: +In the presence of extensions, it is possible for a type to have multiple ways to +conform to an interface. In this case, Slang will always prefer the more specific conformance +over the generic one. For example, the following code illustrates this behavior: ```csharp +interface IBase{} interface IFoo { int foo(); } -struct MyFoo1 : IFoo + +// MyObject directly implements IBase: +struct MyObject : IBase, IFoo { int foo() { return 0; } } -extension IFoo + +// Generic extension that applies to all types that conforms to `IBase`: +extension<T:IBase> T : IFoo { - int bar() { return 0; } + int foo() { return 1; } } -struct MyFoo2 : IFoo + +int helper<T:IFoo>(T obj) { - int foo() { return 0; } - int bar() { return 1; } + return obj.foo(); } -void test() + +int test() { - MyFoo1 f1; - MyFoo2 f2; - int a = f1.bar(); // a == 0, calling the method in the extension. - int b = f2.bar(); // b == 1, calling the existing method in `MyFoo2`. + MyObject obj; + + // Returns 0, the conformance defined directly by the type + // is preferred. + return helper(obj); } ``` + This feature is similar to extension traits in Rust. |
