AaC Inheritance¶
Version 0.4.0
changed how inheritance works in AaC. AaC now provides a more “standard” inheritance construct within the schema
data declaration using the extends
field. By “standard”, we mean you can extend your schema
in the same way you would extend a Python class since AaC uses Python under the hood.
In short, you can extend schemas using an object-oriented mindset. That said, this only applies to schema
. While it is technically possible to extend an Enum
in Python, AaC does not support enum
extension. This may be revisited in the future, but initial attempts to support Enum extension in the underlying Python code generation did not work. And of course, extending primitives is not a thing, but you can define new primitives.
Modeling AaC Inheritance¶
Let’s take a look at how AaC supports Schema
inheritance.
Example AaC Schema extension:
schema:
name: Shape
package: aac.shapes
modifiers:
- abstract
fields:
- name: area
type: number
- name: perimeter
type: number
We’ve defined a generic Shape
schema above. All shapes have a perimeter and area value, so the generic Shape
schema also has a perimeter and area field. Shapes which inherit from Shape
will also inherit these fields.
Below, we will define other schemas which inherit from Shape
:
schema:
name: Triangle
package: aac.shapes
extends:
- name: Shape
package: aac.shapes
fields:
- name: side_one_length
type: number
- name: side_two_length
type: number
- name: side_three_length
type: number
- name: height
type: number
---
schema:
name: Circle
package: aac.shapes
extends:
- name: Shape
package: aac.shapes
fields:
- name: radius
type: number
---
schema:
name: Rectangle
package: aac.shapes
extends:
- name: Shape
package: aac.shapes
fields:
- name: length
type: number
- name: height
type: number
Each of the above schemas have their own properties that help distinguish them as their specific shape. But they all require a perimeter and area field as a valid shape, and so inherit from Shape
.
Inheritance Modifiers¶
Just as in most programming languages, the AaC language provides some basic modifiers to control what you can and can’t do with inherited schema
definitions.
abstract
- This attribute allows declaring a schema as an abstract type. This means it cannot be “instantiated” directly in a definition. In AaC, this means the schema is either a root type or field in anotherSchema
.final
- This allows declaring a schema as a final type, meaning it cannot be extended by anotherSchema
. In AaC this means the final schema cannot appear in another schema’s extends field.
To use these inheritance modifiers you simply add them to the modifiers
field of the schema
. Let’s take another look at the above example to see how it works:
schema:
name: Shape
package: aac.shapes
modifiers:
- abstract
fields:
- name: area
type: number
- name: perimeter
type: number
As you can see, the Shape
schema has an abstract
modifier. This means that Shape
can no longer be instantiated on its own. To make a shape, you must create or use a schema which inherits from Shape
.
name: Square
package: aac.shapes
extends:
- name: Rectangle
package: aac.shapes
modifiers:
- final
fields:
- name: length
type: number
requirements:
- "SQR-1"
---
req:
The above Square
schema inherits from Rectangle
as well via inheriting from Rectangle
, but it has a final
modifier. This means that no other schema can inherit from Square
.
Using Inheritance¶
Now that we can define inheritance, how can we use it. The intended use case is to allow polymorphism in your field declaration. Let’s look at another example to explain.
schema:
name: Pattern
package: aac.shapes
fields:
- name: name
type: string
- name: shapes
type: typeref(aac.shapes.Shape)[]
The above pattern schema has a shapes
field which takes in a number of shapes to create a pattern with.
Since we cannot instantiate the Shape
schema on its own, we must use a schema which extends Shape
. Since the field takes in any Shape
, however, we can use any schema which extends Shape
.