Extents and Types

[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.]

The following guidelines provide best practices for using extents and types in Microsoft code name “M” code.

Do Declare the Structure of Extents Inline when Possible

It is not necessary to first define a type definition for an extent unless there are important aspects of an extent that are used by other types or extents. Instead, define the fields and constraints of an extent inline. Declare reference fields using the referenced extent name. The following “M” code shows how to define two related extents inline without using separate type definitions.

People :
{
    Name : Text where value.Count <= 100;

    HomeAddress : Addresses?;

    WorkAddress : Addresses?;

}* where identity Name;

Addresses : 
{
    Id : Integer32 = AutoNumber();
        
    Street : Text;

    Street2 : Text?;
        
    City : Text;

    State : Text where value.Count == 2;

    Zip : Text where value.Count <= 9;

}* where identity Id;

The preceding example does not declare a Person type and an Address type. Instead, the Persons extent and the Addresses extent are defined directly. Note that the HomeAddress field and the WorkAddress field both refer directly to the Addresses extent.

Consider Factoring Reusable Aspects of an Extent into a Type

When fields and constraints are common to multiple extents, consider factoring these into a discrete type that declares these fields. As a rule, a type should be introduced only if the underlying semantics associated with the fields are similar in each use, not just when fields have the same name and data type. This is often indicated by the fields using similar constraints or being processed in a similar manner. Note that when including a type in the definition of a different extent or type, you can further constrain the fields of the included type.

The following “M” code demonstrates this technique. The System module contains a reusable Item type. This type specifies two common fields, Id and Folder. The Person type uses the type ascription operator, the colon, to conform to the Item type. Other types and extents can also reuse the Item type to obtain the same fields and constraints.

import System;

type Person : Item
{
    FirstName : Text where value.Count <= 100;

    LastName : Text where value.Count <= 100;
        
    DaytimePhone : Text where value.Count <= 20;

}

Friends : 
(
    Person &
    {
        HomeAddress : Addresses?;

        HomePhone : Text where value.Count <= 20;
            
        PersonalWebSiteURL : Text?;

    }

)*;

Customers : 
(
    Person &
    {
        WorkAddress : Addresses?;

        Employer : Text?;

    }

)*;

Addresses : 
(
    Item & 
    {
        Street : Text;

        Street2 : Text?;

        City : Text;

        State : Text where value.Count == 2;

        Zip : Text where value.Count <= 9;

    }

)*;

Consider Factoring Reusable Types into a Separate Module

Types that have potentially broad usage across many modules should be declared in their own module and exported. This module can then be imported by other modules as required. The following “M” code demonstrates this technique. This example is factors out the Person type into a separate Contacts module. This module can then be imported into other source files to reuse the Person type definition.

module Contacts
{
    import System;
    
    export Person;
    
    type Person : Item
    {
        FirstName : Text where value.Count <= 100;

        LastName : Text where value.Count <= 100;
        
        DaytimePhone : Text where value.Count <= 20;
        
    }
}

module Friends
{
    import System;
    import Contacts;

    Friends : 
    (
        Person &
        {
            HomeAddress : Addresses?;

            HomePhone : Text where value.Count <= 20;
            
            PersonalWebSiteURL : Text?;

        }
    )*;
    
    Addresses : 
    (
        Item & 
        {
            Street : Text;

            Street2 : Text?;

            City : Text;

            State : Text where value.Count == 2;

            Zip : Text where value.Count <= 9;

        }
    )*;
}

Note

Note that these modules are shown together for clarity. In practice, these modules, types, and extents should each reside in their own source files. This complies with “M” guidelines for source files. For more information, see Source File Content.

See Also

Other Resources

"M" Coding Conventions