Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interfaces and abstract classes in F#

Tags:

f#

I'm trying to create a small piece of code in F#. The idea is that I would have an interface which defines a few methods, properties, and events. Using this interface I want to define an abstract class (having a generic type) which would implement some properties/methods but not all of the members defined in the interface. The responsibility to define all of the members would be on the derived classes.

So far I'm stuck with the interface and the abstract class. The problems I'm having:

  • The abstract class definition does not recognize the interface definition
  • I'm not sure how to define the abstract members for the interface in the abstract class

The interface compiles fine but the abstract class has several errors. The messages are included in code

All comments, corrections, hints, etc are appreciated. Since this is my first trial on F# there are probably a lot of mistakes to point out.

The code I have so far

Interface definition

namespace A
    type IValueItem =
        interface    
            [<CLIEvent>]
            abstract member PropertyChanged : 
                Control.IEvent<System.ComponentModel.PropertyChangedEventHandler, 
                              System.ComponentModel.PropertyChangedEventArgs>

            abstract ConvertedX : double with get, set

            abstract Y : double with get, set

            abstract member CreateCopy : obj

            abstract member NewTrendItem : obj
        end

And the abstract class

namespace A
    [<AbstractClass>]
    type ValueItem<'TX>() =

        [<DefaultValue>]
        val mutable _y : double

        let _propertyChanged = new Event<_>()

        // ERROR: This type is not an interface type
        // ERROR: The type 'obj' is not an interface type
        // ERROR: The type 'IValueItem' is not defined
        interface IValueItem with

            // ERRROR No abstract or interface member was found that corresponds to this override   
            [<CLIEvent>]
            member this.PropertyChanged : 
                    Control.IEvent<System.ComponentModel.PropertyChangedEventHandler, 
                                    System.ComponentModel.PropertyChangedEventArgs> 
                = _propertyChanged.Publish

            // This definition is incomplete, should be abstract
            member ConvertedX : double with get, set

            // ERROR: Incomplete structured construct at or before this point in pattern
            member CreateCopy() : obj

            member NewTrendItem() : obj

        abstract X : 'TX with get, set

        member this.Y
            with get() = this._y
            and set(value) =
                if this._y <> value then
                    this._y <- value
                    this.NotifyPropertyChanged("Y")

        member this.NotifyPropertyChanged(propertyName) =
                this.PropertyChanged.Trigger(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName))
like image 761
user6423491 Avatar asked Jun 04 '16 16:06

user6423491


People also ask

What are interfaces and abstract classes?

The Abstract class and Interface both are used to have abstraction. An abstract class contains an abstract keyword on the declaration whereas an Interface is a sketch that is used to implement a class.

What is the difference between abstract class and interface in Python?

An abstract class can contain both abstract and non-abstract methods, whereas an Interface can have only abstract methods. Abstract classes are extended, while Interfaces are implemented.

What is difference between interface and abstract class in java 8?

Type of variables: Abstract class can have final, non-final, static and non-static variables. The interface has only static and final variables. Implementation: Abstract class can provide the implementation of the interface. Interface can't provide the implementation of an abstract class.


1 Answers

The abstract class definition does not recognize the interface definition

The interface must be declared above the abstract class, either: in a referenced project/assembly, in a file above your current file (order of files matters), or above in the same file.

I'm not sure how to define the abstract members for the interface in the abstract class

Unfortunately we have to implement all members of the interface, to keep the behavior you want you can have the implementation call an abstract member of the class that has the same signature:

type IValueItem =
    [<CLIEvent>]
    abstract PropertyChanged : 
        Control.IEvent<System.ComponentModel.PropertyChangedEventHandler, 
                        System.ComponentModel.PropertyChangedEventArgs>

    abstract ConvertedX : double with get, set

    abstract Y : double with get, set

    abstract CreateCopy : obj

    abstract NewTrendItem : obj

[<AbstractClass>]
type ValueItem<'TX>() =
    let mutable y = 0.0

    let propertyChanged = Event<_, _>()

    interface IValueItem with

        [<CLIEvent>]
        member __.PropertyChanged : Control.IEvent<_, _> = propertyChanged.Publish

        member this.ConvertedX 
            with get() = this.ConvertedX 
            and set(x) = this.ConvertedX <- x 

        member this.CreateCopy = this.CreateCopy
        member this.NewTrendItem = this.NewTrendItem

        member this.Y
            with get() = this.Y 
            and set(y) = this.Y <- y

    abstract ConvertedX : double with get, set
    abstract CreateCopy : obj
    abstract NewTrendItem : obj

    member this.Y
        with get() = y
        and set(value) =
            if y <> value then
                y <- value
                this.NotifyPropertyChanged("Y")

    abstract X : 'TX with get, set

    member this.NotifyPropertyChanged(propertyName) =
        propertyChanged.Trigger(this, System.ComponentModel.PropertyChangedEventArgs(propertyName))

The Y property is defined twice which looks a bit odd at first. The interface implementation defers to the implementation on the class - this means that to access Y you won't need to upcast an instance of the class to the interface, I've done this to maintain the same behavior as your initial example

To your comment:

To get a virtual member on an abstract class you need to declare the member as abstract and provide a default implementation, here's an example to match the code in your comment:

type IValueItem =
    abstract NewTrendItem : unit -> obj

[<AbstractClass>]
type ValueItem<'TX>() =
    interface IValueItem with
        member this.NewTrendItem() = this.NewTrendItem()

    abstract NewTrendItem : unit -> obj 
    default __.NewTrendItem() = null

type NumberItem() = 
    inherit ValueItem<double>() 

    override __.NewTrendItem() = new NumberItem() :> obj

Generally OO F# is used to interact with the rest of the .NET world - that looks like the case here. But if the code isn't interacting with another .NET API that requires an OO interface, you may find modelling the problem with a functional approach might result in some cleaner code. OO in F# might not give an initial good impression of the language (although personally I quite like the explicitness and brevity of it)

like image 130
Matthew Mcveigh Avatar answered Nov 08 '22 23:11

Matthew Mcveigh