Chapter 18. RSE features

Table of Contents

Attribute
Command
Creator
Event

Attribute

Description

An attribute is a reference to an object of a defined type and belongs to an object or a service.

For example, a customer object could have attribute identifier of type positive32, and attribute name of type string. Or, service XML_utilities could have attribute tag_open of type string.

Each attribute is accessed through its identifier which must be unique within the object or service.

In case of an attribute belonging to an object, the interface to the attribute (i.e. the way how the attribute can be accessed and used) is defined in the object's type, and the implementation of the attribute is defined in the factory that implements the object's type. Hence, in our above example of attribute name in a customer object, the attribute's interface is defined in type customer, and the implementation is defined in factory customer.

In case of an attribute belonging to a service, the attribute's interface and implementation are both defined in the service.

Syntax

Table 18.1. Attribute

ProductionSyntaxLinks
attribute

"attribute" ( "id" ":" ) ? attribute_id attribute_properties
   check_script ?
   default_script ?
   get_script ?
   set_script ?
"end" "attribute" ?

the section called “Attribute”

As we can see from the above syntax, an attribute has a number of properties. Their usage depends on whether the attribute is defined in a type, a factory or a service. The following table shows a summary of all properties.

Table 18.2. Attribute properties

PropertyValueRequiredDefault valueDefined in typesDefined in factoriesDefined in services
ida prefixed identifieryes yesyesyes
typeany existing typeyes yes(1)yes
voidableyes or nononoyes(1)yes
checkan expression or a scriptnovoidyes(1)yes
defaultan expression or a scriptnovoidyes(1)yes
privateyes or nononono(1)yes
kindone of the following:
variable
  constant
  readonly_variable
  readonly_constant
noconstantyes(1)yes
setableone of the following:
all
  factory
  service
  creator
  none
no(2)yes(1)yes
getscript used to get the attribute's valueyes if property kind is readonly_variable or readonly_constantscript that returns the attribute's valuenoyesyes
setscript used to set the attribute's valueyes if property kind is variablescript that sets the attribute's valuenoyesyes
obsoleteyes or nononoyesnoyes if not private attribute

(1): yes if attribute is private, no if attribute is not private

(2): default value for property setable is defined as follows:

Table 18.3. default value for property setable

if ...then default value is
property kind is set to constantcreator
property kind is set to variable and attribute is used in serviceservice
property kind is set to variable and attribute is used in type or factoryfactory
property kind is set to readonly_variable or readonly_constantnone

All properties will now be explained.

Property id

The value of property id is an attribute identifier used to reference the attribute. Each id must be unique within an object or service. An attribute identifier is a prefixed identifier starting with a_ as prefix. For more information about prefixed identifiers see the section called “Prefixed identifier”.

Attribute property type

The value of property type defines the attribute's type, i.e. the type of the object referenced by the attribute.

example:

type product_2

   attribute identifier type:positive32 end
   attribute name type:string end
   attribute price_in_cents type:positive32 end
   
end

Attribute property voidable

The value of property voidable defines whether the value void is allowed for the attribute. By default, void is not allowed, which means that a runtime error will immediately occur whenever an attempt is made to set the attribute's value to void.

example:

type product_3 default_factory:yes

   attribute identifier type:positive32 end
   attribute name type:string end
   attribute price_in_cents type:positive32 voidable:yes end
   
end

In the above example, the value of attribute price_in_cents can be void at runtime (voidable:yes), but all other attributes cannot be void

See also: Chapter 6, Void values

Attribute property check

Property check is used to define which values are allowed for the attribute. Each attempt to set the attribute to an invalid value at runtime (i.e. a value that doesn't pass the check) will immediately result in a runtime error.

There are two ways to define this property:

  1. by an expression that must evaluate to yes for any valid value (used in simple cases)

    example:

    type customer_2 default_factory:yes
       attribute identifier type:positive32 check: i_identifier >= 10000 and i_identifier < 100000 end
       attribute name type:string check: i_name.item_count >= 3 end
    end type

    In the above example identifier must be a value between 10000 and 99999, and name must contain at least 3 characters. Hence, writing:

    var customer_2 garfield = fa_customer_2.co_create ( &
       identifier = 123 &
       name = "Garfield" )

    will immediately generate a runtime error because 123 is an invalid value for identifier.

  2. by a script that evaluates if the value is valid (used in more complex cases)

    example:

    type customer_3
    
       attribute identifier type:positive32
          check
             script
                var positive32 min; max
                // retrieve minimum and maximum values from database:
                //   connect to database
                //   min = ...
                //   max = ...
                //   disconnect from database
                check i_identifier >= min and i_identifier <= max
             end script
          end check
       end attribute
          
       attribute name type:string check: i_name.item_count >= 5 end
    
    end type

In both cases it is also possible to optionally specify:

  • a specific error_message to display to the user (overrides the default error message; can be used by UI frameworks).

  • a specific error_id used to programmatically identify the error, e.g. for logging purposes and statistics.

  • a specific error_data object that holds any useful information which can programmatically be explored. By default, error_data simply contains the value to be checked.

example:

type customer_4

   attribute identifier type:positive32
      check
         script
            var positive32 min; max
            // retrieve minimum and maximum values from database:
            // ...
            check i_identifier >= min and i_identifier <= max &
               error_message: "Identifier must contain a value between " & v_min.to_string & " and " & v_max.to_string & "!" &
               error_id: invalid_identifier &
               error_data: fa_resource_positive32_min_max_error.co_create ( &
				  resource = void &
                  data = i_identifier &
                  min = v_min &
                  max = v_max )
         end script
      end check
   end attribute
      
   attribute name type:string &
      check: i_name.item_count >= 5 &
         error_message: "The name must contain at least 3 characters!" &
         error_id: invalid_name
   end attribute

end type
[Note]Note
Checks are one of the most important features for writing more reliable code in Obix. See Chapter 4, Contract Programming, also called Design by Contract (TM) for more information.

See also:

Property attribute_check

Sometimes the validity of one attribute value depends on the values of one or more other attributes, that is to say there is a mutual dependency of the validity of several attributes. In such a case we have to use property attribute_check.

Because attribute_check concerns several attributes, this property doesn't belong to a single attribute, such as the check property in the previous section, but it belongs to the type or service in which the attributes are defined.

The syntax of attribute_check is defined as follows:

Table 18.4. attribute_check

ProductionSyntaxLinks
attribute_list_check

-> "attribute_check" check_property "end"

-> "attribute_check"
      script
   "end" "attribute_check" ?

the section called “Property attribute_check

There are two ways to define this property:

  1. by an expression that must evaluate to yes (used in simple cases)

  2. by a script that contains any number of check instructions and other instructions (used in more complex cases).

In both cases it is also possible to optionally specify:

  • a specific error_message to display to the user (overrides the default error message; can be used by UI frameworks).

  • a specific error_id used to programmatically identify the error, e.g. for logging purposes and statistics.

  • a specific error_data object that holds any useful information which can programmatically be explored.

Example 18.1. attribute_check example

Suppose that a graphical user interface (GUI) library (or framework) supports automatic resizing of visual objects. For example, the width of a text input field increases automatically whenever the user increases the width of the window that contains the text input field. Many GUI libraries implement this feature with so-called layout managers who are responsible for defining the sizes of the visual objects. For that purpose, each visual object has a minimum size, maximum size, and preferred size, and the actual size on screen is computed by the layout manager who has to respect all visual objects' constraints. It is clear that for each visual object the maximum size must always be greater or equal to the minimum size, and the preferred and actual sizes must always be between the minimum and maximum sizes. As we can see, the validities of attributes depend on each other, so we have to use an attribute_check.

As the size of a two-dimensional visual object is composed of a width and a height, we decide to define types widthable and heightable. widthable could be coded as follows:

type GUI_widthable

   attribute_list type:zero_positive32
      attribute minimum_width end
      attribute maximum_width end
      attribute preferred_width end

      attribute width kind:variable end // actual width on screen
   end

   attribute_check
      script
         check i_preferred_width >= i_minimum_width and i_preferred_width <= i_maximum_width
         check i_width >= i_minimum_width and i_width <= i_maximum_width
      end script
   end attribute_check

end type
[Note]Note
It is not necessary to check the condition i_minimum_width <= i_maximum_width, because both checks above imply this condition.

Type heightable would be defined analogously to type widthable. To show both possibilities, the following type uses an attribute_check expression, instead of an attribute_check script:

type GUI_heightable

   attribute_list type:zero_positive32
      attribute minimum_height end
      attribute maximum_height end
      attribute preferred_height end

      attribute height kind:variable end // actual height on screen
   end

   attribute_check check: &
      i_preferred_height >= i_minimum_height and i_preferred_height <= i_maximum_height and &
      i_height >= i_minimum_height and i_height <= i_maximum_height end

end type

See also:

Attribute property default

Property default defines the attribute's value in case no value is explicitly defined in the source code.

As for property check, there are two ways to define this property:

  1. by an expression (used in simple cases)

    example:

    type customer_5 default_factory:yes
       attribute identifier type:positive32 end
       attribute name type:string default: "unknown" end
    end type

    In the above example name will be "unknown" if no other value is explicitly defined when the object is created. Thus, name will be "unknown" when we code:

    var customer_5 unknown_customer = fa_customer_5.co_create ( &
       identifier = 123 )

    and name will be "Ron" in the following case:

    var customer_5 ron = fa_customer_5.co_create ( &
       identifier = 123 &
       name = "Ron" )
  2. by a script whose output argument holds the default value (used in more complex cases)

    example:

    type customer_6
    
       attribute identifier type:positive32
          default
             script
                var positive32 last_used_identifier
                // retrieve last used identifier from database:
                // last_used_identifier = ...
                o_identifier = last_used_identifier + 1
                // save o_identifier to database
             end script
          end default
       end attribute
          
       attribute name type:string end
    
    end type

See also:

Attribute property private

Factories and services can contain private attributes which cannot be accessed from the outside, but which are needed internally by the factory or service. This property is not used in types.

For an example, please refer to Example 17.6, “Two creators and a private attribute in a factory”

Attribute property kind

Property kind defines how the attribute's value can be read and written, as shown in the following table:

Table 18.5. Attribute property kind

value of property kindread/write permissions
attribute belongs to an objectattribute belongs to a service
constantvalue is defined when object is created, and cannot be changed afterwardsvalue is defined the first time the service is used, and cannot be changed afterwards
variableinitial value is defined when object is created, but value can be changed afterwardsinitial value is defined the first time the service is used, but value can be changed afterwards
readonly_constantvalue is defined through a get script that must always return the same value
readonly_variablevalue is defined through a get script that can return a different value each time it is invoked

example:

type person
   attribute first_name type:string kind:constant end            // first name never changes
                                                                 // ('kind:constant' could be omitted, 
                                                                 // because 'constant' is default value for 'kind')
   attribute last_name type:string kind:variable end             // last name can change, e.g. when woman gets maried
   attribute birthdate type:date end                             // birthdate never changes ('kind' defaults to 'constant')
   attribute age type:zero_positive32 kind:readonly_variable end // age changes each year, and depends on birthdate
end type
[Note]Note
The default value for property kind is constant because objects in Obix are immutable by default. For more information see Chapter 7, Object immutability.

Attribute property setable

If property kind is set to variable, then property setable defines which scripts are allowed to change the attribute's value, according to the following table:

Table 18.6. Attribute property setable

Value of property setableDescription
allvalue can be changed by any script
factoryvalue can only be changed by a script in the factory that creates the object holding the attribute
servicevalue can only be changed by a script in the service holding the attribute
creatorvalue can only be changed by the creator script in the factory that creates the object holding the attribute
nonevalue cannot be changed after initial value has been set

example:

type person_2 default_factory:yes

   attribute_list type:string

      attribute first_name end             // attribute is immutable. it can only be set in the creator.
                                           // (property 'kind' defaults to 'constant', in which case
                                           // property 'setable' defaults to 'creator')
      attribute last_name &
         kind:variable setable:factory end // only scripts in the factory that creates the object can change 'last_name'

      attribute city &
         kind:variable setable:all end     // any script can change the value

   end attribute_list

end type

See also:

Attribute property get

The value of property get is a script that defines and returns the attribute's value. This script is executed each time the attribute's value is read. A get script is used whenever the attribute's value is not simply a reference to an object stored in memory, but has to be determined by a more or less complex script.

example:

service stock_market
   attribute current_dow_jones_index type:positive32 kind:readonly_variable
      get
         script
            // connect to webservice and retrieve index
            // o_dow_jones_index = ...
         end
      end
   end
end

The above script to retrieve the Dow Jones index from a webservice will be executed each time the attribute's value is read, such as when executing:

var positive32 dow_jones_index = se_stock_market.a_current_dow_jones_index
[Note]Note
In Obix attributes are always accessed with the syntax object.attribute_id (e.g. customer.name), even if a get script is defined. There are no so-called "getters" like customer.getName() in Java, C# and other languages.

See also:

Attribute property set

The value of property set is a script that is executed each time the attribute's value is changed. A set script is used whenever the attribute's value is not simply a reference to an object stored in memory.

example:

service GUI
   attribute default_font_size type:positive32 kind:variable setable:all
      get
         script
            // retieve value from XML file
            // o_default_font_size = ...
         end
      end
      set
         script
            // write i_default_font_size to XML file
         end
      end
   end attribute
end service
[Note]Note
In Obix attribute values are always set with the syntax object.attribute_id = <expression> (e.g. customer.city = "Luxembourg"), even if a set script is defined. There are no so-called "setters" like customer.setCity("Luxembourg") in Java, C# and other languages.

See also:

Attribute property obsolete

Setting property obsolete to yes is a hint for the programmer to not use the attribute anymore. The attribute will possibly disappear in a future version of the software. The compiler might display a warning in case the attribute is used, but setting obsolete to yes doesn't change the behavior of the program.

example:

type person_3
   attribute_list type:string
      attribute name obsolete:yes end // replaced by first_name and last_name
      attribute first_name end
      attribute last_name end
   end
end type