Explicit Interface Implementations
When a Class or Record declares that it implements an Interface, the compiler will by default map members declared in the type to those required by the interface, using name and signature:
type
IFoo = public Interface
method Bar;
end;
Foo = public class(IFoo)
method Bar; // automatically maps to IFoo.Bar
end;
Sometimes, this behavior is not desirable, and the implements
Member Modifier can be used to override it by explicitly providing a mapping from members to their interface equivalent.
Explicitly Implementing Individual Members
Individual members can be mapped to an interface member that they don't match by name, by using the implements
modifier, combined with the name of the interface and the name of the interface member it should be mapped to:
type
IFoo = public Interface
method Bar;
end;
Foo = public class(IFoo)
method Bar;
method Baz; implements IFoo.Bar; // explicitly maps to IFoo.Bar
end;
This can be be helpful in a variety of situations, for example if
- the type already contains a different member of the same name that is not related to the interface
- the type implements two or more interfaces that expect a member of the same name (but require different implementations)
- the name required by the interface does not make sense on the context of other members of the class, or could cause confusion
When an explicit mapping is provided, the member is accessible by its real name, when calling it on a reference of the type itself, and on via the interface's name when calling it on an interface reference:
var f := new Foo();
f.Bar; // calls Foo.Bar
f.Baz; // calls Foo.Baz
var g: IFoo := f;
g.Bar; // calls Foo.Baz
Platform Considerations
Due to platform limitations, Explicit Interface Members are only supported on the .NET and Island platforms. On Cocoa and Java, interface members must match in name.
Delegating the Implementation of an Entire Interface
The implements
modifier can also be used to delegate the implementation of an entire interface to a different type stored in a Field or Property of the type. This can be helpful to reuse an existing implementation of an interface in multiple places, or to be able to "switch out" concrete implementations of the interface at runtime (by assigning a different value to the field or property):
type
IFoo = public Interface
method Foo;
method Bar;
method Baz;
end;
Foo = public class(IFoo)
method Foo;
method Bar;
method Baz;
end;
MyClass = public class(IFoo)
public
var fFoo: Object; implements IFoo;
end;
In the above example, the Foo
class provides a complete implementation of IFoo
. MyClass
declares the interface as well, bu does not provide its own implementation for the three methods. Instead, it delegates that implementation to the fFoo
field.
var m := new MyClass();
m.Foo; // compiler error, Foo is not accessible here
(m as IFoo).Foo; // calls fFoo.Foo
By default, members from a deferred interface implementation are not available on the type itself, but only through the interface. Optionally, a Visibilty Modifier can be provided to make the interface members available on the class, as well:
MyClass = public class(IFoo)
public
var fFoo: Object; implements public IFoo; // members of IFoo are publicly available on MyClass
var fBar: Object; implements private IBar; // members of IBar are only privately available
end;
var m := new MyClass();
m.Foo; // now allows call to fFoo.Foo
Platform Considerations
Due to platform limitations, Deferred Interface Implementations on the Cocoa and Java must specify visibility.
See Also
- Interface Types
implements
Member Modifier- Interface Delegation in Mercury