Monday, November 12, 2018

Puppet 6 type system Object attributes

Puppet 6 type system Object attributes

Puppet 6 Type System - More about Object Attributes


This is the second posting in the series about the Object data type in the Puppet Type System - Pcore. The first post introduced the Object data type and the history behind Pcore. You probably want to read that first.

In this post I am going to show how attributes of Objects work in more detail.

Recap Defining an Object data type in Puppet

As you may recall from the earlier post - an Object data type can be created like this in Puppet:

type Car = Object[attributes => {
  reg_nbr => String,
  # ...

(And, if done in Ruby, the part between the brackets goes into the interface section of the create_type body (see the first post).)

When defining an Object, the above can be shortened:

# The brackets can be omitted
type Car = Object {attributes => { reg_nbr => String }}
# The type Object can be omitted
type Car = {attributes => { reg_nbr => String }}


Attributes are the instance/member variables of instances of an Object data type and they come in different flavours: required, optional, derived (two kinds), constant and they can be marked as being an override or being final - all explained below.

Recap of type creation, creating a new instance, and getting attributes:

# This defines the type
type Car = Object {attributes => { reg_nbr => String }}
# This creates an instance
$a_car = Car('ABC 123')
# This gets that instance's variable/attribute reg_nbr so
# 'ABC 123' will be noticed

Attribute Definition - Short and Long Form

Attribute Name

The name is given as a hash key in both the short and long form.
The attribute’s name is a String and it must be unique within the object among both attributes and operations. This rule extends to its parents attributes and operations as a redeclaration means it is an override of the parent’s definition and it must be marked as such to be accepted. The name must start with a lowercase letter and cannot be qualified (i.e. defined as being in a namespace).

Short Form

You have already seen the short form of attribute definition:

reg_nbr => String

Which is an attribute name to data type mapping. An attribute specified like this is always a regular required attribute. All other kinds of definitions require use of the Long Form.

Long Form

In the long form of attribute declaration the map is from an attribute name to a Hash of attribute options. The equivalence of the short form is this:

reg_nbr => { type => String }

When using the long form there must at least be a definition of type.

Attribute Options

name type meaning
annotations - Advanced: Allows association of annotations - to be explained in a separate blog post
final Boolean A final attribute cannot be overridden in sub types.
kind Enum See “Attribute Kind” below
override Boolean Must be set to true if overriding a parent type attribute or operation, an error is raised if attribute/operation does not exist in a parent type.
type Type An upper cased type reference
value Any A literal default value constrained by kind and type

Note: Inheritance will be covered in a coming blog post and I will explain the importance of final and override then.

Attribute Kind

name meaning
constant The attribute is a constant; cannot be set when creating an instance, must have value specified.
derived The attribute’s value is computed. There must exist a method at runtime to compute the value. The attribute’s value cannot be given when creating an instance.
given_or_derived Same as derived, but the value may be given when an instance is created. Think of this as a computed default value.
reference Advanced: Default is false, and true means that the value is not contained and is thus serialized as a reference to a value that must exist elsewhere (typically in the same serialization). To be explained in another blog post.

Note: derived was covered in the first blog post in this series.

Multi Valued Attributes

Multi valued attributes are simply defined as being of Array/Tuple or Hash/Struct data type where the type parameters are used to constrain the number of allowed values and their data type which can be any type in Pcore.

This is a big win compared to some other modeling technologies where multi valued attributes must be scalars.

type Garage = { attributes => {
  parked_cars => Array[Car]

Union Values are Variants

Since Pcore has a Variant data type; describing that a value must be one out of several possible data types, it is easy to model more complicated data models.

means_of_transportation => Variant[Car, Boat, Bike]

Extra attributes/values

The Object type does not allow “extra attributes” like in some modeling
technologies where it is possible to specify a required set and any named additional extra attributes. With Pcore Object you have to model that
as an Object with a hash attribute where the extra “optional” values go.

Typical Usage

Typically, attributes are either required and can be specified using the short form, or they are optional and can either be specified:

  • in short form using Optional[T] if it is acceptable to have undef as the default value, or…
  • in long form with type and value (if default value should be something other than undef). In this case the type should not be Optional[T] unless you want to be able to explicitly assign undef even if default value is something else.

Here is an example showing different kinds of attributes:

type Person = { attributes => {
  # name is required
  name => String,

  # optional with undef default value
  nick_name => Optional[String],

  # fav color is optional and defaults to 'blue'
  fav_color => {
    type => Enum['blue', 'red', 'green'],
    value => 'blue', 
  # avg_life_expectancy is a constant
  avg_life_expectancy => {
    type => Float,
    kind => constant,
    value => 70.5,    # globally


In this post I covered the details of specifying Object attributes and the various kinds of attributes “required”, “optional”, “constant”, and “derived”. In the next post I will cover inheritance of Object types.

No comments:

Post a Comment