summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-09-04 13:25:37 -0700
committerGitHub <noreply@github.com>2024-09-04 13:25:37 -0700
commitddd29057e48a5b309726750e3daf78bfd073038e (patch)
treea054b99acb87d61ef4818dce5fa837ccfd050288 /docs
parent56a3c028a6725e13a2ae3a724eaee05ad9f4802a (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.md51
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.