-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
128 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
/* | ||
* Ideas for programmable meta objects and meta classes. | ||
* Instead of using the vague and slightly intimidating "meta" word, we'll use "model". | ||
*/ | ||
|
||
/* | ||
* Example A: Vehicles. | ||
* 1. Vehicles have models which describe the shape of their wheels. | ||
* 2. Vehicles have object identity, but the only other distinguishing characteristics of a vehicle are its color and its model. | ||
* 3. Cars are vehicles that have a number of doors, fixed by the model of car, that can be broken off doing stunts. | ||
* 4. Motorcycles are two-wheeled vehicles may optionally have a windshield or a chopper configuration. | ||
* 5. The wheel configuration of a vehicle is extremely often used, because roads only interface with wheels. | ||
* 6. Assume cars and vehicles are allocated frequently, models less so. Optimize space usage. | ||
*/ | ||
|
||
// Preliminaries: wheel configs and colors. | ||
type WheelConfig { | ||
case Unicycle; | ||
case Bicycle; | ||
case Tricycle; | ||
case Quad; | ||
case More(count: u7); | ||
} | ||
enum Color { | ||
BLACK, RED, YELLOW, BLUE | ||
} | ||
|
||
/* | ||
* Option 1: new Virgil syntax for declaring a "model". | ||
* The syntax is: | ||
model MyClass.link { | ||
class MyClass { ... } | ||
} | ||
* A /model/ is the "metaclass" of a class and syntactically has the class nested inside it. | ||
* Every instance of the (inner) class has a reference to an instance of the model (outer) class that created it. | ||
* The two occurrences of "MyClass" in the syntax must be the same valid identifier. | ||
* The "link" name must be a valid identifier or the keyword "model". | ||
* The (outer) model class is like a regular class when used by itself. It can extend another | ||
class, have methods, be instantiated with "new", etc. It just has a special dotted name. | ||
* The inner class "MyClass" has its name available at the top level. Its name is not | ||
"MyClass.link.MyClass"--its "MyClass", because it is the common thing which is frequently written. | ||
* The ".link" part of the model name also indicates the name of a field implicitly declared | ||
in "MyClass" that will point to the enclosing "MyClass.link" instance. | ||
* Instances of "MyClass" can only be allocated in the scope of "MyClass.link". | ||
Their implicit "link" field will be initialized to point to the containing model instance, | ||
which is guaranteed to be non-null and definitely initialized. | ||
*/ | ||
|
||
// Option 1 defining a vehicle. | ||
// A basic vehicle has a color and a model. We store the color directly in the car, but | ||
// factor out the wheel config into the Vehicle.model. | ||
// - vehicle.model points to instance of Vehicle.model, which can't be null | ||
// => can be packed into single 64-bit object | ||
model Vehicle.model(wheels: WheelConfig) { // "Vehicle.model" name lifted to top level | ||
class Vehicle(color: Color) { // "Vehicle" name lifted to top level | ||
def dup() -> Vehicle; // abstrat method to make a copy | ||
} | ||
// no methods here, which means no way to make a Vehicle directly. | ||
} | ||
|
||
// Option 1: define a car, which is a subclass of vehicle. | ||
// Cars are limited in that they always have a quad wheel config. | ||
// Cars are special in that they also have doors. They start having a number of doors dictated by their model. | ||
// Then cars can lose doors in stunts. We want cars to always have a Car.model that stores the number | ||
// of doors cars are expected to start with. | ||
// - Car has a {color} field and a new {doors} field. | ||
// - object header points to an instance of Car.model, which can't be null | ||
// => can be packed into a single 64-bit object | ||
model Car.model(doors: u6) extends Vehicle.model(WheelConfig.Quad) { // "Car.model" name lifted to top level | ||
class Car extends Vehicle { // "Car" name lifted to top level | ||
def var doors: u6; | ||
new(color: Color, doors) super(color) { } | ||
|
||
def dup() -> Car { return Car.new(color, doors); } // makes a copy | ||
def doStunt(random: int -> int) -> this { | ||
if (doors > 0 && random(6) == 0) doors--; // unlucky stunt busted off a door | ||
} | ||
} | ||
// It's only legal to make a Car inside Car.model. | ||
def make(color: Color) -> Car { | ||
return Car.new(color, doors); | ||
} | ||
} | ||
|
||
// Option 1: define a motorcyle, which is a subclass of vehicle. | ||
// Motorcycles are limited in that they always have a bicycle wheel config. | ||
// Motorcycles are special in that they can have a windshield and might be a chopper. | ||
// Motorcycles are not mutable, and they can't do stunts like cars. Motorcycles are | ||
// also limited to Color.BLACK. | ||
model Motorcycle.model(windshield: bool, chopper: bool) extends Vehicle.model(WheelConfig.Bicycle) { | ||
class Motorcycle extends Vehicle(Color.BLACK) { // "Motorcycle" lifted to top level | ||
def dup() -> Motorcycle { return Motorcycle.new(); } // makes a copy | ||
} | ||
// It's only legal to make a Motorcycle in a Motorcycle.model. | ||
def make() -> Motorcycle { | ||
return Motorcycle.new(); | ||
} | ||
} | ||
|
||
// Example usages of the above definitions. | ||
def main() { | ||
def v1 = Vehicle.new(); // ERROR: illegal outside model | ||
|
||
def m1 = Vehicle.model.new(WheelConfig.Bicycle); // create new model of vehicle | ||
|
||
def m2 = Car.model.new(4); // create new 4-door car model | ||
def c1: Car = m2.make(Color.RED); // create new red car | ||
assert(m2 == c1.model); // every car remembers its model | ||
var r = c1.doStunt().doStunt(); // do two stunts in a row | ||
|
||
def m3 = JetCar.model.new(JetEngineDesign.TURBOFAN); // create a new jetcar model | ||
def c1: Car = m3.make(Color.RED); // create a new jetcar, which is just a Car | ||
|
||
def m4 = Motorcyle.model.new(true, false); // create a new motorcycle model | ||
def mc1 = m4.make(); // create a new motorcycle | ||
} | ||
|
||
// This file has a secret jet engine project! | ||
private enum JetEngineDesign { | ||
TURBOFAN, AERO_SPIKE | ||
} | ||
|
||
// Option 1: define a private JetCar.model, which is a special kind of model. | ||
// JetCar models can only have 2 doors. | ||
// Private means it cannot be named outside this file. | ||
private model JetCar.model(jet: JetEngineDesign) extends Car.model(2) { | ||
// JetCar instances are not special (i.e. no subclass of Car). Only the model is special. | ||
} |