XTCLANG GUIDES
How to use Type Parameters and Virtual Child Classes in Ecstasy
xtclang
type parameter
virtual classes
Authored by: Abby Sassel, Cameron Purdy
Last edited: @February 10, 2024
About this guide
Explore the more advanced features of the Ecstasy type system, with this guide to type parameters and virtual child classes. By the end of this guide, you will be able to identify and understand some of Ecstasy's more advanced class definitions.
Topics:
- Introduction to type parameters with examples
- Design considerations with Ecstasy type parameters
- Introduction to virtual child classes with examples
Target Audience
This guide is suitable for developers familiar with other languages in the C-family, and with a basic understanding of how classes are defined in Ecstasy.
If you'd like to understand more about the basics of Classes in Ecstasy first, we suggest you start with earlier guides on Defining Classes and Class Keywords first.
Type Parameters
Type parameters in Ecstasy are similar to type parameters in C# and template parameters in C++, and the syntax is also very similar to type parameters in Java, although Java type parameters are erased (the type information only exists at compile time). The List
and Map
examples earlier in this chapter provide a sufficient overview of the similarities with other languages, so let's just look at some specific design considerations with Ecstasy type parameters:
- Each type parameter automatically creates a property of the same name. For example,
class Bag<Element extends Replicable>
means thatBag
will have anElement
property of typeType<Replicable>
that will contain the actual type provided to the type parameter. - Type parameters can be used both as "left hand side" and "right hand side" types. For example, continuing with the
class Bag<Element extends Replicable>
example above, it would be legal to write:Element e = new Element();
, even though the actual type ofElement
is not known by the compiler. (The terms "left hand side" and "right hand side" do not have a single definition, but they are often used to specify the use of a type or a variable either on the left hand or the right hand side of an assignment operation; the concepts are also related to the terms "l-value" and "r-value", referring to something that can be assigned to, and something that can be assigned from, respectively.) - Type parameters make new classes. As already explained,
List<Element>
is a class, and whileList<String>
is still aList
class, it actually defines a different class thanList<Element>
. The term "specializes" is sometimes used in languages with type parameters when the compiler automatically cut-and-pastes all of theList
code for you for every single differentElement
type; for example, "List<String>
is a specialization of theList
class." But that is not what we mean; it's not that the class is cut-and-pasted; it's just thatList<String>
is a separate, different, unique class. - Type parameters are shared by a class with its virtual child classes. Consider the interface
Map<Key, Value>
and its virtual child interfaceEntry
: TheEntry
interface does not have its ownKey
andValue
type parameters, because its class exists contextually within aMap
class. This is a subtle but important difference: There is a classMap<Int, String>.Entry
, but there is no such class asMap.Entry<Int, String>
.
Virtual Child Classes
The concept of virtual child classes, as illustrated by the Map.Entry
example, extends beyond just sharing type parameters. While we won't go into a great amount of technical details at this point, virtual (i.e. non-static
) child classes are virtual in much the same manner that virtual methods are virtual.
Instead of going into depth on this topic here, we'll just give one example to whet your appetite:
module VirtualChildExample {
@Inject Console console;
void run() {
new SuperClass().doSomething();
new SubClass().doSomething();
}
class SuperClass {
void doSomething() {
new Child().printSomething();
}
class Child(String name="superclass") {
void printSomething() {
console.print($"{name} child");
}
}
}
class SubClass
extends SuperClass {
@Override
class Child(String name="subclass");
}
}
Look carefully at the code: Nowhere does it ever say new SubClass.Child()
. Yet when it's run, the output indicates otherwise:
superclass child
subclass child
The line of code that says "new Child()" instantiates the child class, virtually.
At this point, we've only covered a small fraction of the topic of how classes are defined, but it should be enough to provide context for the subsequent chapters.
EXPLORE & LEARN
Ready to learn more?
Check out our latest guides, blogs and tutorials!