Prototypes are the cornerstone of ProtoScript, serving as the fundamental units for modeling data, behavior, and relationships within the Buffaly system’s graph-based framework. If you’re familiar with C# or JavaScript, you can think of Prototypes as a hybrid of classes and objects, but with a twist: they are dynamic, graph-based entities that can act as both templates and instances, inherit from multiple parents, and adapt at runtime. This section introduces Prototypes, their key characteristics, and how they enable flexible knowledge representation, drawing analogies to familiar programming concepts and providing examples to illustrate their power.
A Prototype in ProtoScript is a node in a directed graph that encapsulates:
- Properties: Stored data, like fields in a C# class, representing attributes or relationships (e.g., a city’s name or state).
- Behaviors: Functions that compute results or modify the graph, similar to methods.
- Relationships: Edges to other Prototypes, defining inheritance, properties, or computed links.
Unlike C# classes, which are static templates for creating objects, Prototypes blur the line between template and instance. A Prototype can be used directly (like a singleton) or instantiated to create new nodes, each inheriting its structure and behavior. This flexibility makes Prototypes ideal for modeling diverse domains, from code structures to natural language semantics.
For C# developers:
- A Prototype is like a class that can also act as an object. Imagine defining a
Cityclass with fields and methods, but you can useCityitself as an entity or create instances likeNewYork_Citythat inherit and extend it. - Unlike C#’s single inheritance, Prototypes support multiple parents, similar to interfaces but with richer property and behavior inheritance.
For JavaScript developers:
- Prototypes resemble JavaScript’s prototypal inheritance, where objects inherit directly from other objects. However, ProtoScript Prototypes are organized in a graph, not a linear chain, and include structured properties and functions for symbolic computation.
For database developers:
- Think of a Prototype as a node in a graph database (e.g., Neo4j), with properties as attributes and edges as relationships. ProtoScript adds programming logic, making these nodes programmable and dynamic.
Prototypes are designed to be versatile and expressive, with the following defining features:
-
Dual Role as Template and Instance
- A Prototype can define a reusable structure (like a C# class) and be used directly as an entity (like an object).
- Example: The
CityPrototype defines properties for all cities, butCityitself can represent a generic city in queries, or you can instantiateNewYork_Cityfor specific use.
-
Multiple Inheritance
- Prototypes can inherit from multiple parent Prototypes, combining their properties and behaviors without the restrictions of C#’s single inheritance.
- Example:
Buffalo_Citycan inherit from bothCityandLocation, gaining properties likeStateandCoordinates.
-
Stored (Extensional) Relationships
- Properties store data as edges to other nodes or values, representing fixed facts, similar to database records.
- Example:
NewYork_City.State = NewYork_Statecreates a direct link in the graph.
-
Computed (Intensional) Relationships
- Functions define dynamic relationships or behaviors, computed at runtime by traversing or modifying the graph, akin to methods but graph-centric.
- Example: A function might determine if a city is in a specific state by checking its
Stateproperty.
-
Dynamic Runtime Modifications
- Prototypes can be modified at runtime—adding properties, changing inheritance, or updating relationships—unlike C#’s static type system.
- Example: You can dynamically add a
Populationproperty toCityduring execution.
-
Graph-Based Structure
- Prototypes form a directed graph (often a directed acyclic graph, or DAG, for inheritance, with cycles allowed in property relationships), where nodes are Prototypes and edges represent inheritance or properties.
- Example: The graph links
NewYork_CitytoNewYork_Stateand back, forming a cycle viaState.Cities.
Here’s a simple ProtoScript example to illustrate Prototypes, relatable to object-oriented programming:
prototype City {
System.String Name = "";
State State = new State();
}
prototype NewYork_City : City {
Name = "New York City";
}
prototype State {
Collection Cities = new Collection();
}
prototype NewYork_State : State {
Cities = [NewYork_City];
}
NewYork_City.State = NewYork_State;
What’s Happening?
Cityis a Prototype defining a template withNameandStateproperties, like a C# class.NewYork_Cityinherits fromCity, setting itsNameto "New York City."Statedefines aCitiescollection, andNewYork_Statelinks toNewYork_City.- The assignment
NewYork_City.State = NewYork_Statecreates a bidirectional relationship, forming a cycle in the graph. - C# Equivalent: Imagine a
Cityclass with aStatefield and aStateclass with aList<City>field, but ProtoScript allows runtime modifications and multiple inheritance.
This example shows how Prototypes model real-world entities as graph nodes, with edges representing relationships, offering more flexibility than traditional classes.
In ontology terms, Prototypes are akin to classes or individuals, but with dynamic capabilities:
- Classes: Like OWL classes, Prototypes define concepts (e.g.,
City), but they can evolve at runtime without redefining the ontology. - Individuals: Prototypes like
NewYork_Cityact as instances, linked to other nodes via properties, similar to RDF triples. - Reasoning: ProtoScript uses structural generalization (e.g., comparing instances to find common patterns) rather than formal axioms, making it more adaptable for evolving knowledge bases.
For example, the City/State graph above resembles an ontology with object properties (City.State, State.Cities), but ProtoScript’s runtime flexibility allows adding new properties or relationships without schema changes, unlike OWL’s static structure.
To further illustrate, consider modeling characters from The Simpsons:
prototype Person {
System.String Gender = "";
Location Location = new Location();
Collection ParentOf = new Collection();
}
prototype Homer : Person {
Gender = "Male";
Location = SimpsonsHouse;
ParentOf = [Bart, Lisa, Maggie];
}
prototype Marge : Person {
Gender = "Female";
Location = SimpsonsHouse;
ParentOf = [Bart, Lisa, Maggie];
}
prototype SimpsonsHouse : Location {
System.String Address = "742 Evergreen Terrace";
}
What’s Happening?
Personis a Prototype with properties forGender,Location, andParentOf, like a C# class with fields.HomerandMargeinherit fromPerson, setting specific values and linking toSimpsonsHouse.SimpsonsHouseis aLocationnode, connected toHomerandMargevia theirLocationproperties.- Graph View: The graph links
HomerandMargetoSimpsonsHouseand their children (Bart,Lisa,Maggie), forming a network of relationships. - Database Equivalent: This resembles a relational database with tables for
PersonandLocation, but ProtoScript’s graph allows dynamic queries and modifications.
This example demonstrates how Prototypes can model complex, interconnected entities, making them suitable for knowledge representation tasks.
Internally, Prototypes operate within a graph-based runtime:
- Nodes: Each Prototype is a node with a unique identifier, storing properties and functions.
- Edges: Relationships are edges, including:
- Inheritance Edges:
isalinks to parent Prototypes (e.g.,NewYork_City isa City). - Property Edges: Links to other nodes or values (e.g.,
NewYork_City.State → NewYork_State). - Computed Edges: Functions create dynamic links at runtime.
- Inheritance Edges:
- Graph Structure: The runtime manages a directed graph, typically a DAG for inheritance, but allows cycles in property relationships (e.g.,
City ↔ State). - Instantiation: Creating a new Prototype (e.g.,
new City()) clones the node, copying properties and establishing new edges as needed.
This graph-centric approach enables ProtoScript to handle dynamic, real-world relationships more naturally than traditional object-oriented systems, where hierarchies are fixed and cycles are restricted to object references.
Prototypes can adapt at runtime, a feature not easily achievable in C#:
prototype Buffalo {
System.String Name = "Buffalo";
}
// Dynamically add a type
Typeofs.Insert(Buffalo, Animal);
// Add a property
prototype Color;
prototype Red : Color;
Buffalo.Properties[Color] = Red;
What’s Happening?
Buffalostarts as a simple Prototype with aName.Typeofs.InsertaddsAnimalas a parent, makingBuffalo typeof Animaltrue.- A
Colorproperty is dynamically added, linkingBuffalotoRed. - C# Equivalent: This would require reflection or dynamic types, which are less straightforward and less integrated than ProtoScript’s native support.
- Graph View: The runtime updates the graph, adding an
isaedge toAnimaland a property edge toRed.
This example highlights Prototypes’ flexibility, allowing developers to evolve their models as requirements change.
Prototypes empower developers to:
- Model Complex Relationships: Capture real-world complexity, like bidirectional state-city links, with ease.
- Adapt Dynamically: Modify structures at runtime, ideal for evolving domains like AI or data integration.
- Unify Diverse Domains: Represent code, language, or concepts in a single graph-based framework.
- Enable Reasoning: Support structural generalization and categorization, as explored in later sections.
For developers, Prototypes offer a familiar yet powerful abstraction, combining the structure of classes with the flexibility of graphs, making ProtoScript a versatile tool for modern applications.
Prototypes can model programming constructs, such as a C# variable declaration:
prototype CSharp_VariableDeclaration {
CSharp_Type Type = new CSharp_Type();
System.String VariableName = "";
CSharp_Expression Initializer = new CSharp_Expression();
}
prototype CSharp_Type {
System.String TypeName = "";
}
prototype Int_Declaration : CSharp_VariableDeclaration {
Type.TypeName = "int";
VariableName = "i";
Initializer = IntegerLiteral_0;
}
prototype IntegerLiteral_0 : CSharp_Expression {
System.String Value = "0";
}
What’s Happening?
CSharp_VariableDeclarationdefines a template for variable declarations, like a C# class.Int_Declarationrepresentsint i = 0, inheriting and setting specific values.IntegerLiteral_0models the initializer0as a node.- Graph View: Nodes link
Int_DeclarationtoCSharp_Type(int) andIntegerLiteral_0(0), forming a hierarchical structure. - Use Case: This could be used for code analysis or transformation, like refactoring
int i = 0to another form.
This example shows how Prototypes unify code representation with graph-based modeling, a theme expanded in later sections.
Prototypes are the foundation of ProtoScript, providing a flexible, graph-based way to model entities and relationships. Next: ProtoScript syntax and features, covering how to define, manipulate, and extend Prototypes using C#-inspired constructs.
Previous: ProtoScript Reference Manual | Next: ProtoScript Syntax and Features