My solution is based on using a variant type with one constructor and pattern matching on it to dig out the FrameworkElement. According to the release notes for the CTP, subsumption (automatic upcasting) is supported for function applications but not list. So it appears you have to do something hoaky like the following to store heterogeneous types in a homogeneous data structure such as the list (this anachronistic terminology comes from my reading of F# for Scientists).

Here is my session

#r "PresentationCore.dll";;

#r "PresentationFramework.dll";;

open System.Windows;;

open System.Windows.Controls;;

let b = Button();;

let l = ListBox();;

let p = StackPanel();;

type control = | Con of FrameworkElement;;

[Con b; Con l] |> List.iter (fun arg -> match arg with | Con c -> ignore (p.Children.Add c));;

By on 10/7/2008 12:05 PM ()

Hi ronayoub,

thanks for pointing out the relevant parts of the CTP release notes - I needed to see that again. You can actually further shorten this to:

1
2
3
4
5
6
let FE elm = elm :> FrameworkElement


[FE b; FE l] |> List.iter (p.Children.Add >> ignore)

which is pretty nice when the number of FrameworkElements is small.

However I was actually looking to find a way to 'inject' FE into the List constructor somehow or cook up my own bespoke List constructor (is this possible??).

One (overkill) method that worked was to use quotation processing (warning: toy code up ahead)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#r "FSharp.PowerPack.dll"

open Microsoft.FSharp.Quotations.Patterns
open Microsoft.FSharp.Quotations.DerivedPatterns


module Seq = 
  let covariant (x: Expr<#FrameworkElement> ) = 
    let rec cov q = 
      seq {
        match q with
        | Sequential(head, tail) ->  yield! cov head; yield! cov tail
        | PropGet(elm, pi, arg)  ->  yield (pi.GetValue(elm, [| |]) :?> FrameworkElement)
        |  _                     ->  do ()    }
      cov x
    
<@ b;l;p @> |> Seq.covariant |> Seq.iter (p.Children.Add >> ignore)

// Generates warning FS0020: This expression should have type 'unit', but has type 'Button'.

I ran into a problem when trying to turn this into a generic function:

1
2
3
4
5
6
7
8
9
10
module Seq = 
  let covariant (x: Expr<#'a> ) = 
    let rec cov q = 
      seq {    
        match q with
        | Sequential(head, tail)  ->  yield! cov head; yield! cov tail
        | PropGet(elm, pi, arg)   ->  yield (pi.GetValue(elm, [| |]) :?> 'a)
        | _                       ->  do ()    }
      cov x
    

This type-checks correctly but causes the error:

1
2
3
// Error: Unable to cast object of type 'System.Windows.Controls.Button' to type  System.Windows.Controls.StackPanel'.

as the function specializes to the sub-type rather than the base class. Perhaps someone else can give attempt to generify this function.

regards,

Danny

By on 10/7/2008 5:15 PM ()

To be honest, I'm in the process of learning F# so I don't understand all the details of your code. However, I found this article that talks a bit about the explicit subtyping in F# under the 6/11 post.

[link:pauillac.inria.fr]

So the original line of code you showed looks like it works with a small modification - you have to subtype every item of the list explicity.

[(b :> FrameworkElement); (l :> FrameworkElement)] |> List.iter (p.Children.Add >> ignore);;

I can't figure out why we can't simply create a FrameworkElement list and put any FrameworkElement dervied object into it. Perhaps someone else has input as to why we have this problem to begin with in the wider context of F# design.

By on 10/8/2008 1:10 PM ()

Briefly, this is still a rough corner in the language; there are various trade-offs involving different strategies for how type inference interacts with array/list literals, and this portion of the language is still under active consideration. For now, you must explicitly upcast when you have objects of different subtypes of a hierarchy that you want to put in an array/list of some base type.

By on 10/8/2008 1:54 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