When I want to use method AddTwo() I need to cast the object of class One to interface IOne:

1
2
let simpleAdd = new One()
let test = (simpleAdd :> IOne).AddTwo(2)

For me this use of method defined in the interface implemented by the class is unacceptable.

Basically because the code that uses class One needs to be aware what interfaces the class implement, and what methods belong to that interface, this just brakes encapsulation.

The problem is that you're actually confusing things. F# enforces encapsulation by making you aware of your interfaces.

What it's trying to tell you is that if you want to do operations on "IOne" types then you should be a bit more explicit about it.

This is one of the cases where type annotations come in handy like this:

1
2
3
4
5
6
7
8
9
10
#light
type IOne = abstract AddTwo : int -> int

type One() =
    interface IOne with
        member this.AddTwo i = i + 2

let addTwo (t:IOne) = t.AddTwo
let test = addTwo (new One())
print_any (test 2)

As you can see the "test" method can seamlessly pass a One as a IOne. And this is should be the common case that who ever is doing an operation know what protocol/interface to follow and you encode that with types when needed.

This is no different than in C# following the rule to use the least specific interface/class possible to get the job done.

It promotes encapsulation by making you think about what is really needed to accomplish a task in essence driving complexity down.

By on 1/15/2009 12:10 AM ()

Hi,
I agree that this is a limitation, but I encounter it only very rarely when writing code in F#. I think it is because if you're writing code in F# (even when using object types and interfaces), you don't need as many classes as in C#, because there is often easier way to solve the problem. If you're required to write very object-oriented code (for example because it is a library used by C# client) then it is probably easier to use C# - but you can still write some core parts in F#.

Anwyay, in the case you mentioned, you can use obejct expressions and achieve the same thing more elegantly:

1
2
3
4
5
6
7
type IOne = 
    abstract AddTwo : int -> int 

let simpleAdd = 
  { new IOne with
      member x.AddTwo(i) = i + 2 }
let test = simpleAdd.AddTwo(2)

I think it is important to keep in mind that the design of F# programs is a bit different then when writing C# programs, but if you find the right way then it becomes very elegant & easy to write. If you want to post some more real-world example of what you're doing then we may give you some better hints!

Hope this helps!
Tomas

By on 10/31/2008 11:16 AM ()

Thanks, however I just want to get elegant code in general.

If you had just one interface and let's say five classes implemnting it, the code would look like jungle. You would have two options:

1) making your code awful by adding additional methods. How to name them?

2) forcing people using your code to cast every object ;) so annoying, and I am not a fan of casting.

I mean that the way the OOP part of F# is now made, brakes many good programming practices. There is no good way to walk around this problem.

Do you know if they are going to address this problem in next release?

By on 10/31/2008 11:44 AM ()

Regarding option 1 and 'how to name', use the exact same name and signature. Then you'll have a class that's much like what you get in C#, the only difference being you have to define both the interface method and the class method (whose implementation just delegates to the interface), whereas in C# you just define the class method (and it automatically fills the interface slot as well).

We'll consider this suggestion for the next release. But I echo Tomas' comment that this doesn't occur too often in practice, especially when programming with 'F# style'.

By on 10/31/2008 12:09 PM ()

I agree that this is less of an issue when you program in a functional style.

IMO, the practical issue here is more about interoperability with C#. Right now I am starting to write new code in my legacy C# code base in F#. One way I have started swaping out some of the old C# code with f# is to impliment interfaces from some of the C# code.

It is probably a good idea to make this transition process (and interoperability in general) as smooth as possible

By on 11/20/2008 9:42 PM ()

Coming from Java & C#, I find having to cast up to the interface type in this situation to be a bit strange and verbose. May be I'll get used to it. Is it possible to eliminate the need to do the upcast? Or is this truly a better design?

1
2
3
4
5
6
7
8
9
type IMathService =
  abstract Multiply : int * int -> int
  
type MathService() =
  interface IMathService with
    member x.Multiply(a:int, b:int) = a * b
    
let math = new MathService() :> IMathService
let result = math.Multiply(5,4)

See F# Manual, 8.5 Interface Specifications and Implementations
"Interface members are called by first casting to the interface type:"
[link:research.microsoft.com]

By on 1/13/2009 1:41 PM ()

You need the upcast. I think the other messages on this thread describe this well in detail.

By on 1/13/2009 2:21 PM ()

Yes, I realize that that the upcast is required in the current design/implementation of F#. I'm curious if there has been any thought to removing the need for an upcast in the design of the F# language. I do not know if that would be a good design decision or not.

By on 1/13/2009 4:43 PM ()

In two of my previous posts I said

We'll consider this suggestion for the next release.

and

I don't know what 'the right/best answer is', but I hope this illuminates the issues that play into the pros and cons of have interface methods automatically show up on concrete class types.

So yes, we will think about it; there are pros and cons and it's not necessarily totally clear to us if it's 'good' or not either.

By on 1/13/2009 4:51 PM ()

Brian -- I appreciate your williingness not to prejudge the issue.

Here's a case where I think having to explicitly upcast causes clutter and interferes with a straightforward way of composing API calls.

For example, suppose Layer, SpecialLayer, Sum, Minimum and Contract all implement IFoo interface which has a single method Foo. Also, Sum and Minimum work on List<IFoo> , and Contract takes an IFoo argument.

I'd like to write:

1
2
3
4
let layer1 = Layer( 100000, 10000)
let layer2 = SpecialLayer( 30000, 15000) 
let layer3 = Sum[ layer1 ; layer2 ]
let contract = Contract( Minimum[ layer1 ; l ayer2 ; layer 3 ]  )

and pass the resulting contract to a solver.

Currently I have to write:

1
2
3
4
5
6
7
let layer1 = Layer( 100000, 10000) :> IFoo

let layer2 = SpecialLayer( 30000, 15000)  :> IFoo

let layer3 = Sum[ layer1 ; layer2 ] :> IFoo

let contract = Contract( Minimum[ layer1 ; l ayer2 ; layer 3 ] :> IFoo  )

to which I say, er, 'fooey'.

David

By on 10/13/2009 5:11 PM ()

This is a separate issue from having to upcast to call methods on IFoo; this is subsumption for list literals. I think you may be happy with us in the near future. :)

By on 10/13/2009 6:47 PM ()

Actually, I'm pretty happy with you guys already, but am always willing to get happier;>

By on 10/13/2009 7:06 PM ()

fyi, we just released with this feature

[link:blogs.msdn.com]

More flexibility for list literals and subtyping

List and array literals may now be used to create collections from elements that are subtypes of the collection element type. For example:

let myControls: (Control list) = [ new Button() ; new TextBox() ]

By on 10/19/2009 2:54 PM ()

Thanks, can write cleaner and clearer code without the casts!

Plus I neverused to knew what 'list literal subsumption' was.

thanks David

ps. On another Oct09 release topic, why do we have to add "when 'a: comparison" -- can't the compiler figure it out? Here's an example --

1
2
3
4
5
6
7
8
9
10
11
    
    type Ordering< 'a > = 
    | Order of 'a * 'a
    | NotComparable

    type PartialOrderedSet<  'a when 'a : comparison >( ordering: Map< 'a, Set < 'a  >  > )  =
        member x.Compare a b =
            match a, b  with
            | a, b when ordering.ContainsKey(a) && ordering.[ a ].Contains(b) -> Order(a,b)
            | a, b when ordering.ContainsKey(b) && ordering.[ b ].Contains(a) -> Order(b,a)
            | _ -> NotComparable
By on 10/23/2009 12:55 PM ()

I think Don plans to blog in detail about the motivation and details of the new equality/comparison constraints in the near future.

By on 10/23/2009 1:40 PM ()

Old thread, but I wanted to ask about something that's related to this.

Consider the followeing code:

1
2
3
4
5
6
7
8
type I1 =
  abstract M1 : string
  abstract M2 : string

type C1 =
  interface I1 with
    override c.M1 = "hello"
    override c.M2 = (c:>I1).M1

Why should I have to upcast to I1 from within the M2 implementation? It is already within the context of the I1 implementation.

I know that naming conflicts could arise if C1 has other methods with the same name, but I think that the implicit behavior in this case would be to resolve names to within the interface first and perhaps downcast to access the same name at class level.

By on 7/4/2010 2:24 PM ()

I recall there was also some vague talk of maybe providing some syntactic sugar for implicit interface implementation, but I don't see anything like that in beta 2. Am I missing something, or is it really not there? If not, is it planned for release?

By on 10/21/2009 9:46 AM ()

No, there is nothing there/planned. Note however that regarding (explicit) interfaces, we have fixed some bugs, e.g. as mentioned in the release notes:

Interface implementations can now be inherited

Interfaces implemented by inherited classes can be used to satisfy interface implementation requirements on a derived class. Code such as the following now compiles without the need to explicitly implement I1 in C2.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type public I1 = 
    abstract V1 : string 
    
type public I2 = 
    inherit I1 
    abstract V2 : string 
    
type public C1() = 
    interface I1 with 
        member this.V1 = "C1" 
 
type public C2() = 
    inherit C1() 
    interface I2 with 
        member this.V2 = "C2"
By on 10/21/2009 10:04 AM ()

tomasp, I think that using additional function to use a part of class's methods is just wrong, and would be hard to understand for someone who has no idea about F#.

brianmcn, You convinced me to stick with option 1), I still thinks that every redundancy is bad, and just asks for mistakes.

Can You summarize why F# doesn't have interfaces and inheritance known in C#?

Btw, I've read "Expert F#", Could You recommend where I can read about good practices in F#?

By on 10/31/2008 12:40 PM ()

C# has explicit interfaces too:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    public interface IFoo
    {
        void Method();
    }
    public class Foo : IFoo
    {
        void IFoo.Method()
        {
        }
        public static void Example()
        {
            Foo foo = new Foo();
            foo.Method();  // does not compile
            (foo as IFoo).Method(); // does
        }
    }

The differences are that in F#, interfaces are implemented explicitly by default, whereas in C# they are not, and that in F# there is no syntax to have one method implement both.

The value of explicit interfaces is that they can help reduce complexity and make code more explicit. With many interfaces, you would never call the method on a concrete object, you would only call it on an object that was already upcast to the type. That is, often you'll have a class implement an interface, not so that a user will new up the class and call the method, but instead because a user will new up the class and hand it to some framework that knows how to process IFoos or whatever. In that case, the framework will just keep a collection of IFoo objects and call those methods. When a user does "myFoo." and the intellisense comes up, if IFoo is implemented explicitly, the IFoo methods don't appear, reducing the user-facing complexity for common user scenarios. (Try newing up some WPF objects and look at the hundreds and hundreds of methods that appear in intellisense. How many of those are you likely to call? How many of those are only there to support interaction with other parts of WPF framework? Wouldn't it be nice if more of those interfaces you don't care about were out of your face?)

On the other hand, there are also cases where the interface methods are also intentionally user-facing. List : IList is a good example. Users who have just newed up a List will call Add(), Clear(), etc. But also general methods that work on arbitrary-concrete-collection ILists will also call these methods. In this case, you don't want the interface to be explicit, you want both the users of the concrete type and users targeting the interface to see the same method.

C# prefers the latter strategy, but has a little-known and little-used syntax support for the former. F# prefers the former strategy, and has no syntax sugar for the latter (which is why you have to 'repeat yourself').

I don't know what 'the right/best answer is', but I hope this illuminates the issues that play into the pros and cons of have interface methods automatically show up on concrete class types.

By on 10/31/2008 2:49 PM ()

Can I plead to the designers and caretakers of F# to keep this the way it is?

Please! For the love of all things simple and clean.

Yes comming from a C++ and C# background I stumbled and fell on this issue, I even started argumenting that it was broken flawed and a complete and utter disgrace.

But I was wrong. Dead wrong. The thing is that the F# behaviour promotes among other things IoC and makes it clear what my dependencies really are. It helps keep methods small and focused.

In the example of using a List<T> as an IList<T> to Add/Clear/DoStuff not having the implicit usage actually helps separate the creating of a concrete class from the abstract filling. And that's a good thing.

It helps us bring forth the structure and beauty of interface segregation and helps us think about what the minimal interface needed for an operation really is.

By on 1/15/2009 12:19 AM ()

I agree with torbjorn.gyllebring 110%!

By on 1/15/2009 11:36 AM ()

Hi,
I think the key point is that in F# you don't usually have classes that implement an interface (that would be used directly by the user of the class) and add lot of new functionality by having additional members.

When you just want to implement an interface then object expressions are often the best option. However you can use classes too - and you don't need casting if you just want to call a method/function that takes the interface as an argument:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 
type IFoo =
  abstract Foo : unit -> unit

let callFoo(f:IFoo) = f.Foo()

type Foo1() =
  interface IFoo with
    override x.Foo() = printfn "Foo1"

type Foo2() =
  member x.Other() = printfn "Other"
  interface IFoo with
    override x.Foo() = printfn "Foo2"

let f1 = new Foo1()
let f2 = new Foo2()

// Call function that works with the interface
callFoo f1
callFoo f2

// we can still use other members
f2.Other()

So, I think that F# just forces you to separate parts of the code that works with interfaces implemented by the class and parts that use additional members.

By on 10/31/2008 12:00 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper