Skip to content

Commit 3de73d8

Browse files
authored
Merge pull request #26 from csyonghe/defaultimpl
Add proposal for interface default implementations.
2 parents ecc36c1 + c43006e commit 3de73d8

File tree

1 file changed

+120
-0
lines changed

1 file changed

+120
-0
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# SP#030: Default Implementation of Interface Methods
2+
3+
## Status
4+
5+
Status: In Experiment
6+
7+
Implementation: [PR 7439](https://github.com/shader-slang/slang/pull/7439), [PR 7458](https://github.com/shader-slang/slang/pull/7458), [PR 7465](https://github.com/shader-slang/slang/pull/7465)
8+
9+
Author: Yong He
10+
11+
Reviewer: Theresa Foley
12+
13+
## Background
14+
15+
Often times, an interface method is implemented trivially for all but a few conforming types. This arises most often when an existing interface
16+
is extended to support an additional feature that is only provided or meaningful for a new type that conforms to the interface. Currently, a
17+
developer must manually duplicate the trivial implementation for all existing types after extending the interface, which is a laborious process.
18+
19+
This proposal is to allow interface methods to have a default implementation, that will be used by a conforming type to satisfy the interface
20+
requirement, if the conforming type does not provide its own implementation of the method. Note that other types of requirements, such as properties, subscript operators, associated types and associated constants are not covered by this proposal and default implementation for these types of requirements will remain unsupported.
21+
22+
## Proposed Solution
23+
24+
We propose to allow interface methods to have a body that serves as the default implementation:
25+
26+
```slang
27+
interface IFoo
28+
{
29+
int getVal()
30+
{
31+
return 0;
32+
}
33+
}
34+
35+
struct Impl : IFoo
36+
{
37+
// OK, using IFoo.getVal() to satisfy the requirement.
38+
}
39+
40+
struct Impl2 : IFoo
41+
{
42+
// OK, overriding the default implementation.
43+
override int getVal() { return 1; }
44+
}
45+
```
46+
47+
Both static and non-static methods can have default implementations.
48+
49+
A default implementation can be marked as `[Differentiable]` for automatic differentiation.
50+
51+
Default implementations is treated as if it is an ordinary function generic on `This` type. The `IFoo` interface above will
52+
be interpreted by the compiler as:
53+
54+
```slang
55+
interface IFoo
56+
{
57+
[HasDefaultImpl(IFoo_getVal_defaultImpl)]
58+
int getVal(); // the requirement.
59+
}
60+
61+
// pseudo syntax:
62+
__generic<This:IFoo>
63+
int IFoo_getVal_defaultImpl(this:This)
64+
{
65+
return 0;
66+
}
67+
68+
struct Impl : IFoo
69+
{
70+
.getVal := IFoo_getVal_defaultImpl<Impl>;
71+
}
72+
```
73+
74+
Note that a method in a confirming type that overrides the default implementation in the interface must be explicitly marked as `override`. Overriding a function that is not declared in any base interfaces is an error.
75+
76+
### `override` in Interfaces
77+
78+
A method with a default implementation in an interface cannot be marked `override`, and will not
79+
override any requirements in the base interfaces. Consider the following:
80+
81+
```slang
82+
interface IBase
83+
{
84+
int getVal() { return 0; }
85+
}
86+
interface IDerived : IBase
87+
{
88+
int getVal() { return 1; }
89+
}
90+
sttruct Impl : IDerived {}
91+
92+
int testBase<T:IBase>(T v)
93+
{
94+
return v.getVal();
95+
}
96+
void main()
97+
{
98+
Impl impl = {};
99+
printf("%d\n", testBase(impl));
100+
}
101+
```
102+
103+
Should the output be `0` (calling `IBase.getVal`) or `1` (calling `IDerived.getVal`)? Both behaviors are reasonable.
104+
For simplicity, the current decision is to treat `IBase.getVal` and
105+
`IDerived.getVal` as distinct requirements, so calling `testBase(impl)` should return `0`, and calling `testDerived(impl)` should return `1`.
106+
That is, the existence of `IDerived.getVal` will not override the requirement from `IBase.getVal`.
107+
108+
Using `override` keyword on an interface method is considered an error.
109+
110+
### Constructors
111+
112+
For simplicity, constructors/initializers are not allowed to have a defualt implementation in interfaces.
113+
114+
### Storage Accessors
115+
116+
`get`, `set` and other storage accessors for properties or subscript operations are not allowed to have a default implementation in interfaces.
117+
118+
## Related Work
119+
120+
Default implementations are proven to be a useful feature and are commonly supported in modern languages. They are allowed in Rust traits Swift protocols, and C# interfaces (since C# 8.0).

0 commit comments

Comments
 (0)