locked
How to use two interface in this kind of writing ? RRS feed

  • Question

  • practicing how to templatize a factory pattern from c++ to F#

    but mimic code has some problems such as

    1. new IConcreteProduct()  <- how it would be in F#

    2. let x = new ConcreteCreatorClass(); <- how to pass instance that use interface to this class?

    3. how to call let y = x.createProduct()?

    4. is it using interface like this "let IConcreteProduct ConcreteProduct = "?

    5. is it writing function for interface like this -- let ConcreteProductPrint = printfn "ConcreteProduct print" ?

    6. any other wrong with the following writing

    mimic code

    open System
    type IProduct =
       abstract member ProductPrint : unit -> unit
       
    type IConcreteProduct =
       abstract member ConcreteProductPrint : unit -> unit
    
    type twoInterface =
        inherit IProduct
        inherit IConcreteProduct
        abstract member createProduct : unit -> unit
    
    type ConcreteCreatorClass() =
       interface twoInterface with
          member this.createProduct() = new IConcreteProduct()
          
    let IProduct Product = 
        let ProductPrint = printfn "Product print" 
        Console.WriteLine("")
        
    let IConcreteProduct ConcreteProduct = 
        let ConcreteProductPrint = printfn "ConcreteProduct print" 
        Console.WriteLine("")
        
    let x = new ConcreteCreatorClass();
    let y = x.createProduct()

    Original code

    template<typename Product, typename ConcreteProduct>  
    class ConcreteCreator  
    {  
    public:  
    
           static Product* createProduct()  
           {  
    	        return new ConcreteProduct();  
           }  
    }; 
    
    Product* p = ConcreteCreator<Product, ConcreteProduct>::createProduct();  
    

     

    • Edited by 沈世鈞 Thursday, January 26, 2012 10:15 AM
    Thursday, January 26, 2012 10:14 AM

Answers

  • Hi, the code I've posted is suitable for class inheritance only.

    To use it with interfaces, you should do the following correction:

    if not(typeof<'a>.IsSubclassOf(typeof<'b>)) && not(typeof<'a>.GetInterfaces().Contains(typeof<'b>)) then raise <| InvalidCastException()
    


    • Marked as answer by 沈世鈞 Tuesday, January 31, 2012 8:33 AM
    Monday, January 30, 2012 11:47 AM
  • .GetType()=(typeof<'b>) <<- that's totally incorrect. GetInterfaces returns an array of interfaces that are supported by specified type. You should use Contains here. It is a LINQ function. To use it, you must open System.Linq
    • Marked as answer by 沈世鈞 Tuesday, January 31, 2012 8:33 AM
    Tuesday, January 31, 2012 8:12 AM

All replies

  • That is impossible in F# to specify that ConcreteProduct must inherit Product as long as they are both generic type parameters, so that compiler would check this. But you may use runtime type casts here to get desired results.

    type IProduct =
       abstract member ProductPrint : unit -> unit
    
    type ConcreteProduct() =
        interface IProduct with
            member this.ProductPrint() = printfn "Concrete product"
    
    type ConcreteCreator<'b, 'a when 'a : ( new : unit -> 'a ) > private () =
        // single type check
        static do if not(typeof<'a>.IsSubclassOf(typeof<'b>)) then raise <| InvalidCastException()
        static member createProduct(): 'b = box(new 'a()) :?> 'b
    
    // this would work
    let product = ConcreteCreator<IProduct, ConcreteProduct>.createProduct()
    // this will at runtime, since ConcreteProduct does not derive from IEnumerable
    let fail = ConcreteCreator<System.Collections.IEnumerable, ConcreteProduct>.createProduct()
    


    Thursday, January 26, 2012 11:08 AM
  • System.TypeInitializationException was unhandled
    Message: 'ConcreteCreator`2'

    at box(new 'a()) :?> 'b

    debug can not see type parameter 'a and 'b

    it seems to cast instance a' into type 'b, it has already checked whether using interface with IsSubclassOf, why need to cast

    i feel the factory is a collection of different abstract type of instances

    • Edited by 沈世鈞 Friday, January 27, 2012 2:06 AM
    Friday, January 27, 2012 2:03 AM
  • > it seems to cast instance a' into type 'b, it has already checked whether using interface with IsSubclassOf, why need to cast

    The fact that we know at runtime, that 'a is subclass of 'b does not mean that compiler can get rid of cast, because compiler acts at compile time.

    By the way, that is fail of F#. C# does support " 'a must be subclass of 'b " constraint. So you can add an auxiliary library in C#, which would not require neither dynamic type check, nor dynamic cast.

     

     

    public class ConcreteCreator<I, C>
        where C: I, new()
    {
        public static I createProduct(){
            return new C();
        }
    }
    
    or this way, whatever you like:
    public class ConcreteCreator<I>
    {
        public static I createProduct<C>() where C: I, new(){
            return new C();
        }
    }

     


    • Edited by lostmsu Friday, January 27, 2012 8:20 AM
    Friday, January 27, 2012 8:14 AM
  • Hi , how to fix error System.TypeInitializationException was unhandled
    it seems can not run
    Monday, January 30, 2012 2:29 AM
  • Hi, the code I've posted is suitable for class inheritance only.

    To use it with interfaces, you should do the following correction:

    if not(typeof<'a>.IsSubclassOf(typeof<'b>)) && not(typeof<'a>.GetInterfaces().Contains(typeof<'b>)) then raise <| InvalidCastException()
    


    • Marked as answer by 沈世鈞 Tuesday, January 31, 2012 8:33 AM
    Monday, January 30, 2012 11:47 AM
  • Hi, run your code, the error at box(new 'a()) :?> 'b

    and the GetInterfaces() do not have contains, it seems GetType() = (typeof<'b>) can be compiled

    open System
    type IProduct =
       abstract member ProductPrint : unit -> unit

    type ConcreteProduct() =
        interface IProduct with
            member this.ProductPrint() = printfn "Concrete product"

    type ConcreteCreator<'b, 'a when 'a : ( new : unit -> 'a ) > private () =
        // single type check
        static do if not(typeof<'a>.IsSubclassOf(typeof<'b>)) && not(typeof<'a>.GetInterfaces().GetType()=(typeof<'b>)) then raise <| InvalidCastException()
        static member createProduct(): 'b = box(new 'a()) :?> 'b

    // this would work
    let product = ConcreteCreator<IProduct, ConcreteProduct>.createProduct()

     

    Tuesday, January 31, 2012 2:36 AM
  • not familiar with list operation after using isAllZeroes list

    it seems that it is not list and can not be used by List, After googled, nothing about list but have List

    just want to find if one of items false and then return false, otherwise return true

    open System
    type IProduct =
       abstract member ProductPrint : unit -> unit
    
    type ConcreteProduct() =
        interface IProduct with
            member this.ProductPrint() = printfn "Concrete product"
    
    let checkTypeList(a : Type[], b) : Boolean =
        let isAllZeroes list = Seq.forall (fun elem -> elem.GetType()=b) a
        let mutable result = true
        result <- List.find (fun item -> item = false) isAllZeroes
        if result = false then
            false
        else
            true
    
    type ConcreteCreator<'b, 'a when 'a : ( new : unit -> 'a ) > private () =
        // single type check
        static do if not(typeof<'a>.IsSubclassOf(typeof<'b>)) && not(checkTypeList(typeof<'a>.GetInterfaces(), typeof<'b>)) then raise <| InvalidCastException()
        static member createProduct(): 'b = box(new 'a()) :?> 'b
    
    // this would work
    let product = ConcreteCreator<IProduct, ConcreteProduct>.createProduct()

     

    • Edited by 沈世鈞 Tuesday, January 31, 2012 4:30 AM
    Tuesday, January 31, 2012 4:29 AM
  • .GetType()=(typeof<'b>) <<- that's totally incorrect. GetInterfaces returns an array of interfaces that are supported by specified type. You should use Contains here. It is a LINQ function. To use it, you must open System.Linq
    • Marked as answer by 沈世鈞 Tuesday, January 31, 2012 8:33 AM
    Tuesday, January 31, 2012 8:12 AM
  • it have contains now, it can run. Marvelous.
    Tuesday, January 31, 2012 8:33 AM