Share via


Declaring Fields

[This content is no longer valid. For the latest information on "M", "Quadrant", SQL Server Modeling Services, and the Repository, see the Model Citizen blog.]

Fields are named values. Fields may or may not represent actual units of storage. Fields defined at the Module level represent actual storage, and are also known as extents. If a field is defined in an entity type, then it represents potential storage that becomes actual storage when an extent of that type is declared.

The Microsoft code name “M” language allows you to initialize the value of a field as part of an entity initializer. However, “M” does not specify any mechanism for changing the value of a field once it is initialized. It is assumed that any changes to field values happen outside the scope of “M”.

Declaring Fields

A field declaration consists of the following elements.

  • The field name is required and is an “M” identifier.

  • The type ascription is optional and specifies the type of the field.

  • The field may optionally specify a default value.

Typed Non-Defaulted Fields

Fields that specify a type ascription, but no default value, are probably the most common form of field declaration. In the following example, the Name field is declared to be of type Text, and it has no default value specified.

module Northwind
{
   type Employee
   {
      Id : Integer32 => AutoNumber();
      Name : Text;
   } where identity Id;
}

Default or Optional Fields

A field declaration can specify a default value for the field. Field declarations with default values do not require entity values that conform to the type to have a corresponding field specified. Such fields are called optional fields. For an example, see the following type definition.

module Northwind
{
    type Point3d 
    {
      X : Number;
      Y : Number;
      Z => -1 : Number; // default value of negative one
    }
}

Because the Z field has a default value, the following type test succeeds.

{ X => 100, Y => 200 } in Point3d

The value { X => 100, Y => 200 } does not contain a field for Z. However, you can apply the type ascription operator in order to specify that it is of type Point3D: ({ X => 100, Y => 200 } : Point3d). Now you can access the Z field as follows.

({ X => 100, Y => 200 } : Point3d).Z

This expression returns the value -1.

If a field declaration in an entity type does not specify a default value, then for an entity value to conform to that type, it must specify a value for that field.

Default values are typically written using the explicit syntax shown for the Z field of Point3d in the preceding example.

Nullable Fields and Defaults

If the type of a field is nullable (for example, the nullable postfix operator ? is appended to the type name), then there is an implicit default value (null) for the declaring field.

For example, consider this type.

    type PointND 
    {
      X : Number;
      Y : Number;
      Z : Number?;        // Z is optional
      BeyondZ : {Number*};  // BeyondZ is optional too
    }

Again, the following type test succeeds.

{ X => 100, Y => 200 } in PointND

Ascribing the PointND to the value allows you to get these defaults.

({ X => 100, Y => 200 } : PointND).Z == { }       
({ X => 100, Y => 200 } : PointND).BeyondZ == { } 

The choice of using a nullable type instead of an explicit default value to model optional fields, is not entirely a matter of style. One difference is that using the nullable type allows the extent to get initialized to any value at all, including the value null. Whereas explicitly stating a default means that the extent gets initialized to that value. And if you specify a default on a non-nullable type, then that field can never take on the value null.