There is an interesting use case for intersection types arising from real-world library code. Specifically, when I want one type to "inherit" another. For example, we currently have something like this in DOM.wy:
public type Node is &{
// Identifies what kind of node this i
int nodeType,
// Read only property returns node name
string nodeName,
...
}
public type Element is &{
// Identifies what kind of node this i
int nodeType,
// Read only property returns node name
string nodeName,
...
// Access children
(Element)[] children,
...
}
The intention is that an Element is a Node. One way to support this would using intersection types as follows:
public type Element is &{
// Access children
(Element)[] children,
...
} & Node
This then (effectively) expands to the original type we had for Element. There are a bunch of obvious and immediate issues:
Constraint Types. A type pos&nat would only make sense if either pos <: nat or pos :> nat (or perhaps they had a least upper bound) Otherwise, it doesn't correspond to an existing type.
Records. Intersecting records only makes sense if they are open (or identical).
Variables. Intersecting against (universal) type variables is a thorny issue which should be handled with care. Initially, this doesn't need to be supported. However, eventually, we want bounds on type variables and this is related to that.
NOTE:One of the key challenges with intersection types is how they interact with the existing compiler infrastructure.
For example, we need to check whether an intersection is sensible or not (e.g. int&bool is not). Secondly, is the question of how we represent them within the compiler. We could, for example, always expand them to their full (semantic) type. This would work for everything except type variables, but leads to less comprehensible error messages. If we keep them at the semantic level, then we have to think about what happens when we need to e.g. extract a record type using Type.as().
(see also #68)
There is an interesting use case for intersection types arising from real-world library code. Specifically, when I want one type to "inherit" another. For example, we currently have something like this in
DOM.wy
:The intention is that an
Element
is aNode
. One way to support this would using intersection types as follows:This then (effectively) expands to the original type we had for
Element
. There are a bunch of obvious and immediate issues:pos&nat
would only make sense if eitherpos <: nat
orpos :> nat
(or perhaps they had a least upper bound) Otherwise, it doesn't correspond to an existing type.NOTE: One of the key challenges with intersection types is how they interact with the existing compiler infrastructure.
For example, we need to check whether an intersection is sensible or not (e.g.
int&bool
is not). Secondly, is the question of how we represent them within the compiler. We could, for example, always expand them to their full (semantic) type. This would work for everything except type variables, but leads to less comprehensible error messages. If we keep them at the semantic level, then we have to think about what happens when we need to e.g. extract a record type usingType.as()
.