2

I would like to create an F# seq and ensure that each element is of record type SelctionDescriptor<'a> for some arbitrary type 'a. I know how to do this OOP style: define the seq over an abstract class and then inherit the generic class from it. But how to do this functional style?

I want a covariant seq where each element may be of a different type.

Ganesh Sittampalam
  • 28,821
  • 4
  • 79
  • 98
  • 1
    `seq` ? no need for inheritance – John Palmer Nov 26 '15 at 05:18
  • 1
    you would not use inheritance in C# either ... `IEnnumerable>` will work there as well – Random Dev Nov 26 '15 at 05:29
  • You can't create a seq like that without specifying the type. I want a seq where each element may be of a different type – user3905162 Nov 26 '15 at 05:48
  • 2
    like one of type `SelectionDescriptor` and others `Selectiondescriptor`? Well that's not possible then (Sequences are homogenous) - instead either use the OOP solution or think what you really need form the elements (usually some common data/operations), create a record with these data/ops and make a sequence of those – Random Dev Nov 26 '15 at 05:53
  • 4
    Possible duplicate of [F# and interface covariance: what to do? (specifically seq<> aka IEnumerable<>)](http://stackoverflow.com/questions/4203560/f-and-interface-covariance-what-to-do-specifically-seq-aka-ienumerable) – Mark Seemann Nov 26 '15 at 06:42

1 Answers1

1

As you've currently described the problem, unless 'a is of a regular type, I don't see a type-safe solution available to you in any paradigm. As you noted in your question, you can use a non-generic interface or abstract base class but this approach is probably going to lead you down a route of type testing and unsafe casting at some point - this is definitely not a favourable option.

If you can refactor your descriptor then other options potentially become available. For supporting a variety of different things in a collection, F# is actually opens up some options compared to C# provided that you can specify, in advance, what the possible options are using discriminated unions.

Consider you have a sequence of selection descriptors which might be a float or an int, you could create:

type SelectionDescriptor =
    |SelectionDescriptorInt of int
    |SelectionDescriptorFloat of float

An example as a list:

let test = 
    [SelectionDescriptorInt 3; SelectionDescriptorFloat 7.0; 
     SelectionDescriptorFloat 19.7; SelectionDescriptorInt 0 ]

Then when you inspect the results you could perform pattern matching on each element. This doesn't compromise the type safety of the solution and the compiler will warn us if our checks aren't exhaustive.

Note: It would be very suboptimal to use this approach if the structure of the different items is regular, i.e. if you have int, float, int float, etc. you would be much better off using a seq<int*float> or some other equivalent structured type.

TheInnerLight
  • 12,034
  • 1
  • 29
  • 52