Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: default interface method implementation #16074

Closed
xieguigang opened this issue Dec 22, 2016 · 8 comments
Closed

Proposal: default interface method implementation #16074

xieguigang opened this issue Dec 22, 2016 · 8 comments

Comments

@xieguigang
Copy link

xieguigang commented Dec 22, 2016

Hi, currently the interface definition in .NET just allow define a set of method declaration template, and not allow includes any implentation details. But the java language it does, the interface define in java can includes some default method implentation, and I thinks this feature can introduce in the .NET language too.

Actually, the interface with default method implentation in java language can be simulated in .NET language by using extension method of the interface type or abstract class

For example, using the extension method for this simulation:

<Extension>
Public Function DefaultMethodExample(of T As InterfaceType)(x As T) As .....

' Overrides for a specifc interface implentation class
' Where T2 is a type which implement the interface InterfaceType
<Extension>
Public Function DefaultMethodExample(Of T As T2)(x As T) .......

Or using an abstract class is also works, but the problem is that the abstract class just not allow multiple inherits and the extension method is not so Convenient. So i think this java language feature can be introduce into VB/C#.

This default interface method is useful for some common operations of an interface type, and can save a lot of time from the duplicate coding for this job.

For example, in visualbasic define for the default interface method implementation in Interface with VB Default keyword:

Public Interface IExample(Of T)

Default ReadOnly Property Value(key$) As String
    Get
        Dim s As New Value(Of String)
        Return If("" = (s = GetData(key$)), s, Provider(NameOf(IExample(Of ).Provider & key$)).ToString)
    End Get
End Property

Default Function GetData As NameValueCollection
    Return New NameValueCollection
End Function

Function Provider As Dictionary(Of String, T)

End Interface

Were in this interface its implentation type, can overrides the default method with Overloads keyword:

Public Class T2
Implements IExample(Of String)

Public Overloads Function GetData As NameValueCollection Implements IExample(Of String).GetData
' blablabla
End Function

Public Function Provider As Dictionary(Of String, String) Implements IExample(Of String).Provider
' blablabla
End Function
End Class
@alrz
Copy link
Member

alrz commented Dec 22, 2016

#258

@HugoRoss
Copy link

I don't see any benefit. If you like to provide a default, then why don't you provide an abstract class that implements the interface and that provides some partial implementation? In VB you can ship it together, the abstract class can be an inner class of the interface:

Public Interface ILockable

    ReadOnly Property IsLocked As Boolean
    Sub Lock()

    MustInherit Class DefaultImplementation
        Implements ILockable

        Private _IsLocked As Boolean

        Public ReadOnly Property IsLocked As Boolean Implements ILockable.IsLocked
            Get
                Return _IsLocked
            End Get
        End Property

        Public Sub Lock() Implements ILockable.Lock
            _IsLocked = True
        End Sub

        Protected Sub CheckLocked()
            If (_IsLocked) Then Throw New InvalidOperationException("The instance is locked!")
        End Sub

    End Class

End Interface

Whether this is best practice or not I let up to you to decide. But it's quite elegant to be consumed:

Public Class LockableObject
    Inherits ILockable.DefaultImplementation

    Private _SomeValue As DateTime

    Public Property SomeValue As DateTime
        Get
            Return _SomeValue
        End Get
        Set(value As DateTime)
            CheckLocked()
           _SomeValue = value
        End Set
    End Property

End Class

@aluanhaddad
Copy link

@HugoRoss From a C# perspective, extension methods are fantastic tools. This will not change. They are much more broadly applicable, if less conceptually pure, than default interface methods because they can augment any type and can do it transiently, i.e. when brought into scope by referencing an assembly and/or importing a namespace. However, the use case for default methods is to allow an imbued type to take part in the method selection process by providing its own implementation. They serve different purposes.

@amethyst-asuka
Copy link

Hi , @HugoRoss,

In practice, using abstract class for the default method simulation just partly works:

The disadvantage of abstract class simulate interface default method

1. abstract class can not multiple inheritance

The class can not multiple inheritance but the interface does, so if a class type implement 2 different interface and these 2 interface both have the default method implements, then the abstract class simulation failure to work

2. interface have function alias name, but abstract class it doesn't

For example,

Interface I
    Default Function a As String
        Return "123"
    End Function
End Interface

Class a : Implements I
    Private Overloads Function bb As String Implements I.a
        Return "123"
    End Function
End Class

Class b : Implements I
    Public Overloads Function a As String Implements I.a
        Return "233"
    End Function
End Class

Class c: Implements I
End Class

These function alias all works,

Call DirectCast(New a, I).a.Echo  ' 123
Call DirectCast(New b, I).a.Echo  ' 233
Call DirectCast(New c, I).a.Echo  ' 123

3. interface have function access control, but abstract class it doesn't

The function overrides in class type Inheritance its signature must keeps the same, but the interface method implementation doesn't

MustInherits Class cc : Implements II

    ' All of the interface method is Public access, but we can change its implements function access
    ' But this situation is not allowed in the class inherits 
    Private Function a As String Implements II.Function_b
    End Function

    Protected MustOverrides Function b As String Implements II.a123

    Public MustOverrides Function c As String Implements II.bbb

End Class

All of this access controls from the interface method are works perfectly in VisualBasic

3. abstract class can apply on Structure Type?

NO!

The disadvantage of extension method simulate interface default method

Assume that we have a extension method using as the default method implements for an interface type in namespace a, and another extension method for implements as a default method for a specific interface implements type in namespace b

Namespace a

    Public Module IDefault
        ' This method works for all type that implements interface I
        <Extension> Public Sub DefaultExample(Of T As I)(x As T)   

Namespace b
    Public Module IDefault

        ' This method works for all type c2, and c2 Implements the interface I
        <Extension> Public Sub DefaultExample(Of T As c2)(x As T)   

For example, if we want using the default method in namespace b, and we forget imports the namespace b but imports the namespace a, so that the function that we used for this default method implementation is the function in namespace a, but the function in namespace a is totally differently with the function in namespace b, this will easily makes bugs and makes you app malfunction.

#16074
#8127
#60
#258
#73

@xieguigang
Copy link
Author

@amethyst-asuka yes, this is the point!

@aluanhaddad
Copy link

@amethyst-asuka Indeed. I fully agree. However for extension methods

For example, if we want using the default method in namespace b, and we forget imports the namespace b but imports the namespace a, so that the function that we used for this default method implementation is the function in namespace a, but the function in namespace a is totally differently with the function in namespace b, this will easily makes bugs and makes you app malfunction.

this is actually a great thing.
Again they both serve different purposes.

@gafter
Copy link
Member

gafter commented Jan 6, 2017

Closing as a dup of #258

@gafter gafter closed this as completed Jan 6, 2017
@HugoRoss
Copy link

HugoRoss commented Jan 11, 2017

Hi , @amethyst-asuka,

Reply to "Abstract classes cannnot have multiple inheritance, aliases, change visibility and do not work with structures"

You are right, abstract classes are not that convenient (although they work, of course). Here an example with concrete classes (my new suggestion for handling these cases without adding new syntax to the language).

Interface I1

	Function F1() As String 'has a default
	Function F2() As String 'has no default

	Class DefaultImplementation
		Implements I1

		Public Overridable Function F1() As String Implements I1.F1
			Return "I1.F1()"
		End Function

		Public Overridable Function F2() As String Implements I1.F2
			Throw New NotImplementedException()
		End Function

	End Class

End Interface

Interface I2

	Function F1() As String 'has a default
	Function F2() As String 'has no default

	Class DefaultImplementation
		Implements I2

		Public Overridable Function F1() As String Implements I2.F1
			Return "I2.F1()"
		End Function

		Public Overridable Function F2() As String Implements I2.F2
			Throw New NotImplementedException()
		End Function

	End Class

End Interface

Structure A
	Implements I1, I2

	'Hint: Does not work for structs
	'Private ReadOnly _I1Instance As New I1.DefaultImplementation()
	'Private ReadOnly _I2Instance As New I2.DefaultImplementation()

	Private _I1Instance As I1.DefaultImplementation
	Private _I2Instance As I2.DefaultImplementation

	Private ReadOnly Property I1Instance As I1.DefaultImplementation
		Get
			Dim myResult As I1.DefaultImplementation = _I1Instance
			If (myResult Is Nothing) Then
				myResult = New I1.DefaultImplementation()
				_I1Instance = myResult
			End If
			Return myResult
		End Get
	End Property

	Private ReadOnly Property I2Instance As I2.DefaultImplementation
		Get
			Dim myResult As I2.DefaultImplementation = _I2Instance
			If (myResult Is Nothing) Then
				myResult = New I2.DefaultImplementation()
				_I2Instance = myResult
			End If
			Return myResult
		End Get
	End Property

	Private ReadOnly Property P1 As String
		Get
			Return "P1"
		End Get
	End Property

	Private Function F1() As String Implements I1.F1
		Return I1Instance.F1() & "."c & P1
	End Function

	Public Function OtherF1() As String Implements I2.F1
		Return I2Instance.F1() & "."c & P1
	End Function

	Friend Function F2() As String Implements I1.F2, I2.F2
		Return "F()"
	End Function

End Structure

This example shows a structure that uses default implementations of two different interfaces and changes the visibility of their methods.

(And alright, maybe a slight addition to VB syntax would simplify it...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants