Search code examples
listtypescastingstatic-typingdynamic-typing

What’s the point of mixed-type lists


Some languages like Python allow you to define mixed type lists:

mixed = [1, 'a', 2, 'b']

While other languages would require that all elements of a list be of the same type.

numbers = [1, 2]
letters = ['a', 'b']

My question is: what’s a valid use case of mixed type lists? I’ve only seen them used in examples.

It seems to me that mixing types in a list is not a good practice and if you have need for it, you’d probably be better off refactoring your code.

What am I missing?


Solution

  • An example of a heterogenous list that you have probably seen yourself thousands of times without realizing it, is the argument list of a subroutine call or message send: for example, in

    add_element_to_list(list, element)
    

    The argument list list :: element :: Nil is a heterogeneous list of type List[T] :: T :: Nil.

    You could also represent an argument list as a tuple, i.e. in the above example, the argument list would be the 2-tuple (aka "pair") (list, element) of type List[T] × T, but tuples have some limitations. For example, tuples are generally thought of as a single unit, not a collection. But, there are legitimate reasons you might want to iterate over the arguments in an arguments list.

    Some languages / collections libraries do allow you to iterate over a tuple, for example, in Python, tuples are considered sequence types, and thus are iterable. Scala also has the productIterator method that lets you iterate over any product type (not just tuples).

    But now we're back to square one: if we want to iterate over a tuple, then we need an iterator where the elements it yields can have different types. And an iterator is essentially the same thing as a (lazy) list, so now we have essentially re-introduced heterogeneous lists!

    However, there is a probably more well-known use of heterogeneous lists, or more general, heterogeneous collections: database access.

    The paper Strongly Typed Heterogenous Collections by Oleg Kiselyov, Ralf Lämmel, and Keean Schupke contains not only an implementation of heterogenous lists in Haskell, but also a motivating example of when, why and how you would use HLists. In particular, they are using it for type-safe compile-time checked database access. (Think LINQ, in fact, the paper they are referencing is the Haskell paper by Erik Meijer et al that led to LINQ.)

    Quoting from the introductory paragraph of the HLists paper:

    Here is an open-ended list of typical examples that call for heterogeneous collections:

    • A symbol table that is supposed to store entries of different types is heterogeneous. It is a finite map, where the result type depends on the argument value.
    • An XML element is heterogeneously typed. In fact, XML elements are nested collections that are constrained by regular expressions and the 1-ambiguity property.
    • Each row returned by an SQL query is a heterogeneous map from column names to cells. The result of a query is a homogeneous stream of heterogeneous rows.
    • Adding an advanced object system to a functional language requires heterogeneous collections of a kind that combine extensible records with subtyping and an enumeration interface.

    Note that the Python example you gave in your question is really not a heterogenous list in the sense that the word is commonly used, since Python doesn't have (static) types. It is a weakly typed or untyped list. In fact, in some sense, it is actually a homogenous list, since all elements are of the same type: depending on your interpretation, all elements have no type, all elements have the type Object, or all elements have the type Dynamic – but in all cases, they all have the same type. You are then forced to perform casts or unchecked isinstance tests or something like that, in order to actually be able to meaningfully work with the elements, which makes them weakly typed.