Difference between revisions of "Short BOOPSI Overview"

From MorphOS Library

(Getting an Attribute: get() and xget() clarifications.)
m (Some grammar fixed and small changes for readability.)
Line 2: Line 2:
 
==Object Oriented Programming==
 
==Object Oriented Programming==
  
The object oriented programming is a technique developed as a response for two trends in the computer market. The first one was increasing complexity of software. Management of a traditionally written code becomes harder when the code size increases. The second trend was increasing popularity of graphical user interfaces, which meant the end of the sequential execution of programs. Instead modern programs are '''event driven''', it means the flow of code is determined by external events (like an user input) and is not known at a time of writing the program. Object oriented programming divides a program into a set of objects interacting with each other using well defined interfaces. Such a modularization simplifies the management of project and also fits naturally the concept of modern graphical user interfaces. User controls (called "gadgets" in MUI) are just objects in the code and interact with objects representing user data.
+
Object oriented programming is a technique developed as a response to two trends in the computer market. The first one was increasing complexity of software. Management of a traditionally written codebase becomes harder when the code size increases. The second trend was the increasing popularity of graphical user interfaces, which meant the end of sequential execution of programs. Instead modern programs are '''event driven''', which means the flow of code execution is determined by external events (like user input) and is not known at the time of writing the program. Object oriented programming divides a program into a set of objects interacting with each other using well defined interfaces. Such a modularization simplifies the management of a software project and also fits naturally with the concept of modern graphical user interfaces. User controls (called "gadgets" in MUI) are just objects in the code and they interact with other objects representing user data.
  
This short introduction is not intended to be a complete lecture on object oriented programming. On the other hand no knowledge of any particular object oriented programming language is required to get familiar with BOOPSI.  Usually the support for OOP techniques comes with a programming language, which is either designed for OOP (like C++, C# or Java) or has OOP support added in more or less logical way (Objective C, PHP). This is not the case for BOOPSI and MUI however. In this case object oriented programming support comes from the operating system. BOOPSI and MUI can be used with any programming language, including traditional ones, for example C and even assembler.
+
This short introduction is not intended to be a complete lecture on object oriented programming. On the other hand no knowledge of any particular object oriented programming language is required to get familiar with BOOPSI.  Usually the support for OOP techniques comes with a programming language, which is either designed for OOP (like C++, C# or Java) or has OOP support added in a more or less logical way (Objective C, PHP). This is not the case for BOOPSI and MUI however. In this case object oriented programming support comes from the operating system. BOOPSI and MUI can be used with any programming language, including traditional ones, for example C and even assembler.
  
The BOOPSI module is located in the ''intuition.library'', with some important functions being added from a statically linked ''libabox''. It's primary design goal was to build a framework for wrapping Intuition GUI elements in an object oriented interface. This approach was unfortunately not flexible enough, so MUI uses only basic BOOPSI framework. This framework provides the four basic concepts of the object oriented programming: '''classes''', '''objects''', '''methods''' and '''attributes'''. It also supports class inheritance. Because of it's simplicity, BOOPSI is easy to understand and use, especially when compared to sophisticated frameworks, like the one in the C++ programming language.
+
The BOOPSI module is located in the ''intuition.library'', with some important functions being added from a statically linked ''libabox''. It's primary design goal was to build a framework for wrapping Intuition GUI elements in an object oriented interface. This approach was unfortunately not flexible enough, so MUI uses only the basic BOOPSI framework. This framework provides the four basic concepts of object oriented programming: '''classes''', '''objects''', '''methods''' and '''attributes'''. It also supports class inheritance. Because of it's simplicity, BOOPSI is easy to understand and use, especially when compared to more sophisticated frameworks, like the one in the C++ programming language.
  
  
Line 15: Line 15:
  
 
====Methods====
 
====Methods====
Methods are just actions, which can be performed on an object. A set of available methods is defined by the object's class. Technically speaking, a method is a function called with an object as its parameter and changing the object's state. In BOOPSI, methods are called using ''DoMethod()'' call from ''libabox'':
+
Methods are just actions, which can be performed on an object. A set of available methods is defined by the object's class. Technically speaking, a method is a function called with an object as its parameter in order to change the object's state. In BOOPSI, methods are called using the ''DoMethod()'' call from ''libabox'':
  
 
  result = DoMethod(object, method_id, ... /* method parameters */);
 
  result = DoMethod(object, method_id, ... /* method parameters */);
 
  result = DoMethodA(object, method_struct);
 
  result = DoMethodA(object, method_struct);
  
The first, more popular form of the call just builds the method structure on the fly, from arguments passed. Any method structure has always the method identifier as the first field. ''DoMethodA()'' call gets a pointer to the method structure, the structure is built by the application. This second form is rarely used. The number and meaning of parameters, as well as the meaning of the result are method specific. Comparision of executing a method with both forms of the call is given below:
+
The first, more popular form of the call just builds the method structure on the fly, from arguments passed to it. Any method structure always has the method identifier as the first field. The ''DoMethodA()'' call gets a pointer to the method structure, the structure is built by the application. The second form is rarely used. The number and meaning of parameters, as well as the meaning of the result are method specific. Comparision of executing a method with both forms of the call is given below:
  
 
  struct MUIP_SomeMethod
 
  struct MUIP_SomeMethod
Line 44: Line 44:
  
  
Object's attributes represent its properties. They are set and get using special methods, ''OM_SET()'' and ''OM_GET()'' respectively. It differs from the most of object oriented programming languages, where attributes (being implemented as object's fields) are accessed directly. Manipulating attributes in BOOPSI is slower then, as it implies performing a method.
+
An object's attributes represent its properties. They are written and read using special methods, ''OM_SET()'' and ''OM_GET()'' respectively. This differs from most object oriented programming languages, where attributes (being implemented as an object's fields) are accessed directly. Manipulating attributes in BOOPSI is slower then, as it implies performing a method.
  
 
====Setting an Attribute====
 
====Setting an Attribute====
  
The ''OM_SET()'' method does not take a single attribute and its value, but a [[Taglists|taglist]] of them, so one can set multiple attributes at once. Setting of two attributes to an object may be done as follows:
+
The ''OM_SET()'' method does not take a single attribute and it's value, but a [[Taglists|taglist]] of them, so one can set multiple attributes at once. The setting of two attributes to an object may be done as follows:
  
 
  struct TagItem attributes[] = {
 
  struct TagItem attributes[] = {
Line 58: Line 58:
 
  DoMethod(object, OM_SET, (ULONG)attributes);
 
  DoMethod(object, OM_SET, (ULONG)attributes);
  
It is cumbersome and the code is not easily readable. The ''intuition.library'' makes it easier providing ''SetAttrsA()'' function, which is a wrapper for ''OM_SET()'' method. Using this function and the array defined above, one can write:
+
However, this is cumbersome and the code is not easily readable. The ''intuition.library'' makes it easier by providing the ''SetAttrsA()'' function, which is a wrapper for the ''OM_SET()'' method. Using this function and the array defined above, one can write:
  
 
  SetAttrsA(object, attributes);
 
  SetAttrsA(object, attributes);
  
It still requires definition of a temporary [[Taglists|taglist]], but the function has its variadic form ''SetAttrs()'', which allows for building the taglist on-the-fly:
+
It still requires definition of a temporary [[Taglists|taglist]], but the function also has a variadic (meaning it can take a variable number of arguments) form ''SetAttrs()'', which allows for building the taglist on-the-fly:
  
 
  SetAttrs(object,
 
  SetAttrs(object,
Line 69: Line 69:
 
  TAG_END);
 
  TAG_END);
  
This is not all however. Programmers are lazy and decided that in the common case of setting a single attribute, ''SetAttrs()'' is still too much typing. A common practice found in sources using MUI was to define an ''xset()'' or ''set()'' macro, which is now defined in the system headers, in the ''<libraries/mui/h>'' file.
+
This is not all however. Programmers are lazy and decided that in the common case of setting a single attribute, ''SetAttrs()'' is still too much typing. A common practice found in sources using MUI was to define an ''xset()'' or ''set()'' macro, which is now defined in the system headers, in the ''<libraries/mui.h>'' file.
  
 
  #define set(object, attribute, value) SetAttrs(object, attribute, value, TAG_END)
 
  #define set(object, attribute, value) SetAttrs(object, attribute, value, TAG_END)
Line 77: Line 77:
 
  set(object, MUIA_SomeAttr1, 756);
 
  set(object, MUIA_SomeAttr1, 756);
  
The ''OM_SET()'' method returns a number of attributes applied to the object. If some attributes are not known to the object's class (and superclasses), they are not counted. This return value is usually ignored, it may be used for testing an attribute applicability.
+
The ''OM_SET()'' method returns the number of attributes applied to the object. If some attributes are not known to the object's class (and superclasses), they are not counted. This return value is usually ignored, it may be used for testing an attribute applicability.
  
 
====Getting an Attribute====
 
====Getting an Attribute====
  
The ''OM_GET()'' method gets a single attribute from an object. There is no multiple attributes getting method. Its first, obvious parameter is the attribute identifier. The attribute value is not returned as the result of the method however. Instead the second parameter is a pointer to memory area, where the value is to be stored. This allows for passing attributes larger than 32 bits, they are just copied to the pointed memory area. This only works for fixed size attributes. Text strings cannot be passed this way, so they are passed as pointers (pointer to the string is stored at a place in memory pointed by the second parameter of ''OM_GET()''). The three examples below demonstrate all the three cases:
+
The ''OM_GET()'' method gets a single attribute from an object. There is no multiple attributes getting method. It's first, obvious parameter is the attribute identifier. The attribute value is not returned as the result of the method however. Instead the second parameter is a pointer to a memory area, where the value is to be stored. This allows for passing attributes larger than 32 bits, they are just copied to the pointed memory area. This only works for fixed size attributes. Text strings cannot be passed this way, so they are passed as pointers (a pointer to the string is stored at a place in memory pointed to by the second parameter of ''OM_GET()''). The three examples below demonstrate all three cases:
  
 
  LONG value1;
 
  LONG value1;
Line 91: Line 91:
 
  DoMethod(object, OM_GET, MUIA_Attribute3, (ULONG)&value3);  /* string attr */
 
  DoMethod(object, OM_GET, MUIA_Attribute3, (ULONG)&value3);  /* string attr */
  
In a case when an attribute is returned by pointer, pointed data should be treated as read-only unless documented otherwise.
+
In cases when an attribute is returned by pointer, the data pointed to should be treated as read-only unless documented otherwise.
  
Similarly as for ''OM_SET()'', there is a wrapper function for ''OM_GET()'' in the ''intuition.library'', named ''GetAttr()''. This function unexpectedly changes the order of arguments: attribute identifier is the first, object pointer is the second. The three above examples may be written with ''GetAttr()'' as follows:
+
Similarly as for ''OM_SET()'', there is a wrapper function for ''OM_GET()'' in the ''intuition.library'', named ''GetAttr()''. This function unexpectedly changes the order of arguments: attribute identifier is the first, object pointer is the second. The three examples above may be written with ''GetAttr()'' as follows:
  
 
  GetAttr(MUIA_Attribute1, object, &value1);
 
  GetAttr(MUIA_Attribute1, object, &value1);
Line 101: Line 101:
 
The third parameter, a storage pointer is prototyped as pointer to ULONG, so in the first example type casting is not needed.
 
The third parameter, a storage pointer is prototyped as pointer to ULONG, so in the first example type casting is not needed.
  
The ''<libraries/mui.h>'' system header file defines a macro ''get()'', which reverses order of the two first arguments of ''GetAttr()'' and adds the typecasting to ''ULONG*''. Order of arguments of ''get()'' is the same as for ''set()'', which helps to avoid mistakes. The third line of the above example may be rewritten with ''get()'' this way:
+
The ''<libraries/mui.h>'' system header file defines a macro ''get()'', which reverses the order of the two first arguments of ''GetAttr()'' and adds the typecasting to ''ULONG*''. The order of arguments of ''get()'' is the same as for ''set()'', which helps to avoid mistakes. The third line of the above example may be rewritten with ''get()'' this way:
  
 
  get(object, MUIA_Attribute3, &value3);
 
  get(object, MUIA_Attribute3, &value3);
Line 121: Line 121:
 
  }
 
  }
  
The function is very simple and is compiled to a few processor instructions. That is why it is declared as ''inline'', which makes the compiler to insert the function's code in-place instead of generating a jump. It makes the code faster, albeit bigger a bit. Except of working only with 32-bit attributes, ''xget()'' has a disadvantage of loosing the ''OM_GET()'' return value. The value is boolean and is ''TRUE'' if the object's class (or any of superclasses) recognizes the attribute, ''FALSE'' otherwise. This value is usually ignored, but may be useful for scanning objects for supported attributes.
+
The function is very simple and is compiled to a few processor instructions. That is why it is declared as ''inline'', which causes the compiler to insert the function's code in-place instead of generating a jump. This makes the code faster, albeit a bit bigger. Except for working only with 32-bit attributes, ''xget()'' also has the disadvantage of loosing the ''OM_GET()'' return value. The value is boolean and is ''TRUE'' if the object's class (or any of it's superclasses) recognizes the attribute, ''FALSE'' otherwise. This value is usually ignored, but may be useful for scanning objects for supported attributes.
  
 
<small>The ''xget()'' function is not defined in the system headers. It has been described here because of its common use in MUI applications. Its counterparts for bigger sized arguments may be defined if needed.</small>
 
<small>The ''xget()'' function is not defined in the system headers. It has been described here because of its common use in MUI applications. Its counterparts for bigger sized arguments may be defined if needed.</small>
  
 
==Object Construction and Destruction==
 
==Object Construction and Destruction==

Revision as of 01:13, 5 November 2010

Grzegorz Kraszewski

Object Oriented Programming

Object oriented programming is a technique developed as a response to two trends in the computer market. The first one was increasing complexity of software. Management of a traditionally written codebase becomes harder when the code size increases. The second trend was the increasing popularity of graphical user interfaces, which meant the end of sequential execution of programs. Instead modern programs are event driven, which means the flow of code execution is determined by external events (like user input) and is not known at the time of writing the program. Object oriented programming divides a program into a set of objects interacting with each other using well defined interfaces. Such a modularization simplifies the management of a software project and also fits naturally with the concept of modern graphical user interfaces. User controls (called "gadgets" in MUI) are just objects in the code and they interact with other objects representing user data.

This short introduction is not intended to be a complete lecture on object oriented programming. On the other hand no knowledge of any particular object oriented programming language is required to get familiar with BOOPSI. Usually the support for OOP techniques comes with a programming language, which is either designed for OOP (like C++, C# or Java) or has OOP support added in a more or less logical way (Objective C, PHP). This is not the case for BOOPSI and MUI however. In this case object oriented programming support comes from the operating system. BOOPSI and MUI can be used with any programming language, including traditional ones, for example C and even assembler.

The BOOPSI module is located in the intuition.library, with some important functions being added from a statically linked libabox. It's primary design goal was to build a framework for wrapping Intuition GUI elements in an object oriented interface. This approach was unfortunately not flexible enough, so MUI uses only the basic BOOPSI framework. This framework provides the four basic concepts of object oriented programming: classes, objects, methods and attributes. It also supports class inheritance. Because of it's simplicity, BOOPSI is easy to understand and use, especially when compared to more sophisticated frameworks, like the one in the C++ programming language.


Classes and Objects

Methods and Attributes

Methods

Methods are just actions, which can be performed on an object. A set of available methods is defined by the object's class. Technically speaking, a method is a function called with an object as its parameter in order to change the object's state. In BOOPSI, methods are called using the DoMethod() call from libabox:

result = DoMethod(object, method_id, ... /* method parameters */);
result = DoMethodA(object, method_struct);

The first, more popular form of the call just builds the method structure on the fly, from arguments passed to it. Any method structure always has the method identifier as the first field. The DoMethodA() call gets a pointer to the method structure, the structure is built by the application. The second form is rarely used. The number and meaning of parameters, as well as the meaning of the result are method specific. Comparision of executing a method with both forms of the call is given below:

struct MUIP_SomeMethod
{
  ULONG MethodID;
  LONG ParameterA;
  LONG ParameterB;
};

DoMethod(object, MUIM_SomeMethod, 3, 7);

struct MUIP_SomeMethod mparams = { MUIM_SomeMethod, 3, 7 };
DoMethodA(object, &mparams);

The DoMethod() form is more convenient, so it is commonly used. MUI uses specific prefixes for all its structures and constants:

  • MUIM_ for method identifiers.
  • MUIP_ for method parameter structures.
  • MUIA_ for attribute identifiers.
  • MUIV_ for special, predefined attribute values.


The C types used in the method structure above may need some explanation. LONG is a 32-bit signed integer, ULONG is an unsigned one. Because the structure is usually built on the processor stack, all parameters are extended and aligned to 32 bits. Then every parameter in the structure must be defined either as a 32-bit integer or a pointer. Any parameter larger than 32 bits must be passed via pointer (for example double precision floats or strings).


An object's attributes represent its properties. They are written and read using special methods, OM_SET() and OM_GET() respectively. This differs from most object oriented programming languages, where attributes (being implemented as an object's fields) are accessed directly. Manipulating attributes in BOOPSI is slower then, as it implies performing a method.

Setting an Attribute

The OM_SET() method does not take a single attribute and it's value, but a taglist of them, so one can set multiple attributes at once. The setting of two attributes to an object may be done as follows:

struct TagItem attributes[] = {
  { MUIA_SomeAttr1, 756 },
  { MUIA_SomeAttr2, 926 },
  { TAG_END, 0 }
};

DoMethod(object, OM_SET, (ULONG)attributes);

However, this is cumbersome and the code is not easily readable. The intuition.library makes it easier by providing the SetAttrsA() function, which is a wrapper for the OM_SET() method. Using this function and the array defined above, one can write:

SetAttrsA(object, attributes);

It still requires definition of a temporary taglist, but the function also has a variadic (meaning it can take a variable number of arguments) form SetAttrs(), which allows for building the taglist on-the-fly:

SetAttrs(object,
  MUIA_SomeAttr1, 756,
  MUIA_SomeAttr2, 926,
TAG_END);

This is not all however. Programmers are lazy and decided that in the common case of setting a single attribute, SetAttrs() is still too much typing. A common practice found in sources using MUI was to define an xset() or set() macro, which is now defined in the system headers, in the <libraries/mui.h> file.

#define set(object, attribute, value) SetAttrs(object, attribute, value, TAG_END)

Then, setting a single attribute can be coded as follows:

set(object, MUIA_SomeAttr1, 756);

The OM_SET() method returns the number of attributes applied to the object. If some attributes are not known to the object's class (and superclasses), they are not counted. This return value is usually ignored, it may be used for testing an attribute applicability.

Getting an Attribute

The OM_GET() method gets a single attribute from an object. There is no multiple attributes getting method. It's first, obvious parameter is the attribute identifier. The attribute value is not returned as the result of the method however. Instead the second parameter is a pointer to a memory area, where the value is to be stored. This allows for passing attributes larger than 32 bits, they are just copied to the pointed memory area. This only works for fixed size attributes. Text strings cannot be passed this way, so they are passed as pointers (a pointer to the string is stored at a place in memory pointed to by the second parameter of OM_GET()). The three examples below demonstrate all three cases:

LONG value1;
QUAD value 2;    /* 64-bit signed integer */
STRPTR *value3;

DoMethod(object, OM_GET, MUIA_Attribute1, (ULONG)&value1);  /* integer attr */
DoMethod(object, OM_GET, MUIA_Attribute2, (ULONG)&value2);  /* fixed size big attr */
DoMethod(object, OM_GET, MUIA_Attribute3, (ULONG)&value3);  /* string attr */

In cases when an attribute is returned by pointer, the data pointed to should be treated as read-only unless documented otherwise.

Similarly as for OM_SET(), there is a wrapper function for OM_GET() in the intuition.library, named GetAttr(). This function unexpectedly changes the order of arguments: attribute identifier is the first, object pointer is the second. The three examples above may be written with GetAttr() as follows:

GetAttr(MUIA_Attribute1, object, &value1);
GetAttr(MUIA_Attribute2, object, (ULONG*)&value2);
GetAttr(MUIA_Attribute3, object, (ULONG*)&value3);

The third parameter, a storage pointer is prototyped as pointer to ULONG, so in the first example type casting is not needed.

The <libraries/mui.h> system header file defines a macro get(), which reverses the order of the two first arguments of GetAttr() and adds the typecasting to ULONG*. The order of arguments of get() is the same as for set(), which helps to avoid mistakes. The third line of the above example may be rewritten with get() this way:

get(object, MUIA_Attribute3, &value3);

The most often used attributes are integers (32-bit or shorter) and strings. Both of them fit into a 32-bit variable, as strings have to be passed via pointers. Taking this into account, MUI programmers invented a function (sometimes defined as a macro), which just returns the attribute value instead of storing it at a specified address. The function is named xget() and works as shown below:

value1 = xget(object, MUIA_Attribute1);
/* MUIA_Attribute2 can't be retrieved with xget() */
value3 = (STRPTR)xget(object, MUIA_Attribute3);

The xget() function may be defined in the following way:

inline ULONG xget(Object *obj, ULONG attribute)
{
  ULONG value;

  GetAttr(attribute, object, &value);
  return value;
}

The function is very simple and is compiled to a few processor instructions. That is why it is declared as inline, which causes the compiler to insert the function's code in-place instead of generating a jump. This makes the code faster, albeit a bit bigger. Except for working only with 32-bit attributes, xget() also has the disadvantage of loosing the OM_GET() return value. The value is boolean and is TRUE if the object's class (or any of it's superclasses) recognizes the attribute, FALSE otherwise. This value is usually ignored, but may be useful for scanning objects for supported attributes.

The xget() function is not defined in the system headers. It has been described here because of its common use in MUI applications. Its counterparts for bigger sized arguments may be defined if needed.

Object Construction and Destruction